dot
dotVariants
stableCVA 스타일 타입 안전 컴포넌트 변형 빌더 — base, variants, defaultVariants, compoundVariants 지원
@hua-labs/dotv2.0.0
Import
import { dotVariants } from '@hua-labs/dot';
import type { VariantProps, DotVariantsConfig } from '@hua-labs/dot';Functions
dotVariants
CVA(Class Variance Authority)를 대체하는 변형 스타일 팩토리입니다. 클래스 이름 대신 StyleObject를 반환하며, 타입 안전한 변형 시스템을 제공합니다.
Signature
function dotVariants<V extends VariantShape>(
config: DotVariantsConfig<V>
): DotVariantsFn<V>Parameters
| 파라미터 | 타입 | 설명 |
|---|---|---|
config | DotVariantsConfig<V> | 변형 설정 오브젝트 |
DotVariantsConfig
| 필드 | 타입 | 설명 |
|---|---|---|
base | string | 모든 변형에 공통으로 적용되는 유틸리티 문자열 |
variants | V | 변형 축 정의. 각 키는 변형 이름, 값은 { 변형값: 유틸리티문자열 } 맵 |
defaultVariants | Partial<VariantProps<V>> | 변형이 지정되지 않았을 때 사용할 기본값 |
compoundVariants | CompoundVariant<V>[] | 여러 변형 조건이 동시에 충족될 때 추가로 적용할 스타일 |
Returns
DotVariantsFn<V> — (props?: VariantProps<V>) => StyleObject 형태의 호출 가능한 함수.
Usage
import { dotVariants } from '@hua-labs/dot';
import type { VariantProps } from '@hua-labs/dot';
// 버튼 변형 정의
const buttonStyles = dotVariants({
base: 'inline-flex items-center justify-center rounded-md font-medium transition-colors',
variants: {
variant: {
default: 'bg-primary-500 text-white hover:bg-primary-600',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
outline: 'border border-gray-300 bg-white hover:bg-gray-50',
ghost: 'hover:bg-gray-100',
destructive: 'bg-red-500 text-white hover:bg-red-600',
},
size: {
sm: 'h-8 px-3 text-xs',
md: 'h-10 px-4 text-sm',
lg: 'h-12 px-6 text-base',
},
},
defaultVariants: {
variant: 'default',
size: 'md',
},
});
// 타입 추출
type ButtonVariants = VariantProps<typeof buttonStyles>;
// 사용
buttonStyles();
// base + variant:'default' + size:'md' 적용
buttonStyles({ variant: 'outline' });
// base + variant:'outline' + size:'md' 적용
buttonStyles({ variant: 'secondary', size: 'lg' });
// base + variant:'secondary' + size:'lg' 적용// compoundVariants — 여러 조건이 동시 충족 시 추가 스타일
const badgeStyles = dotVariants({
base: 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium',
variants: {
variant: {
default: 'bg-primary-500 text-white',
secondary: 'bg-gray-100 text-gray-800',
outline: 'border border-gray-300',
},
size: {
sm: 'text-xs px-2 py-0.5',
lg: 'text-sm px-3 py-1',
},
},
defaultVariants: {
variant: 'default',
size: 'sm',
},
compoundVariants: [
// variant가 'outline'이고 size가 'lg'일 때 추가 스타일
{
conditions: { variant: 'outline', size: 'lg' },
dot: 'border-2',
},
],
});
badgeStyles({ variant: 'outline', size: 'lg' });
// base + outline + lg + compoundVariant(border-2) 모두 적용// React 컴포넌트에 통합
import React from 'react';
import { dotVariants } from '@hua-labs/dot';
import type { VariantProps } from '@hua-labs/dot';
const cardStyles = dotVariants({
base: 'rounded-xl border bg-white shadow-sm',
variants: {
padding: {
none: '',
sm: 'p-4',
md: 'p-6',
lg: 'p-8',
},
elevated: {
true: 'shadow-lg',
false: 'shadow-sm',
},
},
defaultVariants: {
padding: 'md',
elevated: 'false',
},
});
type CardProps = VariantProps<typeof cardStyles> & {
children: React.ReactNode;
};
function Card({ children, padding, elevated }: CardProps) {
return (
<div style={cardStyles({ padding, elevated })}>
{children}
</div>
);
}
// 사용
<Card padding="lg" elevated="true">내용</Card>// boolean 변형
const overlayStyles = dotVariants({
base: 'fixed inset-0',
variants: {
visible: {
true: 'opacity-100',
false: 'opacity-0',
},
blurred: {
true: 'backdrop-blur-sm',
false: '',
},
},
defaultVariants: {
visible: 'false',
blurred: 'false',
},
});
overlayStyles({ visible: 'true', blurred: 'true' });
// { opacity: 1, backdropFilter: 'blur(4px)', ... }타입 레퍼런스
VariantShape
type VariantShape = Record<string, Record<string, string>>;DotVariantsConfig
interface DotVariantsConfig<V extends VariantShape> {
base?: string;
variants?: V;
defaultVariants?: { [K in keyof V]?: StringToBoolean<keyof V[K]> };
compoundVariants?: CompoundVariant<V>[];
}CompoundVariant
interface CompoundVariant<V extends VariantShape> {
conditions: { [K in keyof V]?: StringToBoolean<keyof V[K]> };
dot: string;
}VariantProps
type VariantProps<V extends VariantShape> = {
[K in keyof V]?: StringToBoolean<keyof V[K]>;
};Notes
dotVariants()는 클래스 이름이 아닌StyleObject를 반환합니다. 클래스 이름이 필요한 경우dotClass()를 사용하세요.- Flutter 대상(
runtime: 'flutter')은dotVariants()와 호환되지 않습니다.FlutterRecipe는 중첩 오브젝트 구조로 얕은 병합이 불가능합니다. - 변형 스타일은 내부적으로 캐시됩니다. 동일한 유틸리티 문자열을 여러 변형에서 재사용해도 성능 저하가 없습니다.
compoundVariants의 조건은 AND 연산입니다. 모든 조건이 충족될 때만 적용됩니다.