This commit is contained in:
@@ -7,133 +7,133 @@ type ButtonVariant = 'primary' | 'secondary' | 'important';
|
||||
type NativeButtonType = 'button' | 'submit' | 'reset';
|
||||
|
||||
type ButtonProps = {
|
||||
label?: string;
|
||||
type: ButtonType;
|
||||
variant?: ButtonVariant;
|
||||
size?: ComponentSize;
|
||||
to?: string;
|
||||
htmlType?: NativeButtonType;
|
||||
onClick?: MouseEventHandler<HTMLElement>;
|
||||
disabled?: boolean;
|
||||
icon?: ElementType;
|
||||
ariaLabel?: string;
|
||||
className?: string;
|
||||
label?: string;
|
||||
type: ButtonType;
|
||||
variant?: ButtonVariant;
|
||||
size?: ComponentSize;
|
||||
to?: string;
|
||||
htmlType?: NativeButtonType;
|
||||
onClick?: MouseEventHandler<HTMLElement>;
|
||||
disabled?: boolean;
|
||||
icon?: ElementType;
|
||||
ariaLabel?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const SIZE_CLASS: Record<ComponentSize, string> = {
|
||||
sm: 'h-8 px-3 text-xs',
|
||||
md: 'h-10 px-4 text-sm',
|
||||
lg: 'h-12 px-5 text-base',
|
||||
full: 'h-10 w-full px-4 text-sm',
|
||||
sm: 'h-8 px-3 text-xs',
|
||||
md: 'h-10 px-4 text-sm',
|
||||
lg: 'h-12 px-5 text-base',
|
||||
full: 'h-10 w-full px-4 text-sm',
|
||||
};
|
||||
|
||||
const ICON_ONLY_SIZE_CLASS: Record<ComponentSize, string> = {
|
||||
sm: 'h-8 w-8 !p-0',
|
||||
md: 'h-10 w-10 !p-0',
|
||||
lg: 'h-12 w-12 !p-0',
|
||||
full: 'h-10 w-full !p-0',
|
||||
sm: 'h-8 w-8 !p-0',
|
||||
md: 'h-10 w-10 !p-0',
|
||||
lg: 'h-12 w-12 !p-0',
|
||||
full: 'h-10 w-full !p-0',
|
||||
};
|
||||
|
||||
const ICON_CLASS: Record<ComponentSize, string> = {
|
||||
sm: 'h-4 w-4',
|
||||
md: 'h-4 w-4',
|
||||
lg: 'h-5 w-5',
|
||||
full: 'h-4 w-4',
|
||||
sm: 'h-4 w-4',
|
||||
md: 'h-4 w-4',
|
||||
lg: 'h-5 w-5',
|
||||
full: 'h-4 w-4',
|
||||
};
|
||||
|
||||
const ICON_ONLY_CLASS: Record<ComponentSize, string> = {
|
||||
sm: 'h-4 w-4',
|
||||
md: 'h-5 w-5',
|
||||
lg: 'h-6 w-6',
|
||||
full: 'h-5 w-5',
|
||||
sm: 'h-4 w-4',
|
||||
md: 'h-5 w-5',
|
||||
lg: 'h-6 w-6',
|
||||
full: 'h-5 w-5',
|
||||
};
|
||||
|
||||
const TYPE_CLASS: Record<ButtonType, string> = {
|
||||
solid: 'btn-solid',
|
||||
outlined: 'btn-outlined',
|
||||
noborder: 'btn-noborder',
|
||||
solid: 'btn-solid',
|
||||
outlined: 'btn-outlined',
|
||||
noborder: 'btn-noborder',
|
||||
};
|
||||
|
||||
const VARIANT_CLASS: Record<ButtonVariant, string> = {
|
||||
primary: 'btn-primary',
|
||||
secondary: 'btn-secondary',
|
||||
important: 'btn-important',
|
||||
primary: 'btn-primary',
|
||||
secondary: 'btn-secondary',
|
||||
important: 'btn-important',
|
||||
};
|
||||
|
||||
function resolveVariant(type: ButtonType, variant?: ButtonVariant): ButtonVariant {
|
||||
if (variant) {
|
||||
return variant;
|
||||
}
|
||||
if (variant) {
|
||||
return variant;
|
||||
}
|
||||
|
||||
return type === 'solid' ? 'primary' : 'secondary';
|
||||
return type === 'solid' ? 'primary' : 'secondary';
|
||||
}
|
||||
|
||||
export function Button({
|
||||
label,
|
||||
type,
|
||||
variant,
|
||||
size = 'md',
|
||||
to,
|
||||
htmlType = 'button',
|
||||
onClick,
|
||||
disabled = false,
|
||||
icon: Icon,
|
||||
ariaLabel,
|
||||
className = '',
|
||||
label,
|
||||
type,
|
||||
variant,
|
||||
size = 'md',
|
||||
to,
|
||||
htmlType = 'button',
|
||||
onClick,
|
||||
disabled = false,
|
||||
icon: Icon,
|
||||
ariaLabel,
|
||||
className = '',
|
||||
}: Readonly<ButtonProps>) {
|
||||
const isIconOnly = Icon != null && !label;
|
||||
const resolvedVariant = resolveVariant(type, variant);
|
||||
const composedClassName = [
|
||||
TYPE_CLASS[type],
|
||||
VARIANT_CLASS[resolvedVariant],
|
||||
isIconOnly ? ICON_ONLY_SIZE_CLASS[size] : SIZE_CLASS[size],
|
||||
Icon && label ? 'gap-1.5' : '',
|
||||
disabled ? 'pointer-events-none cursor-not-allowed opacity-45 saturate-50' : '',
|
||||
className,
|
||||
]
|
||||
.join(' ')
|
||||
.trim();
|
||||
const computedAriaLabel = ariaLabel ?? label;
|
||||
const iconClass = `${isIconOnly ? ICON_ONLY_CLASS[size] : ICON_CLASS[size]} shrink-0`;
|
||||
const content = (
|
||||
<>
|
||||
{Icon ? <Icon className={iconClass} aria-hidden="true" /> : null}
|
||||
{label ?? null}
|
||||
</>
|
||||
);
|
||||
|
||||
const handleLinkClick: MouseEventHandler<HTMLElement> = (event) => {
|
||||
if (disabled) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
onClick?.(event);
|
||||
};
|
||||
|
||||
if (to) {
|
||||
return (
|
||||
<Link
|
||||
to={to}
|
||||
onClick={handleLinkClick}
|
||||
aria-disabled={disabled}
|
||||
aria-label={computedAriaLabel}
|
||||
tabIndex={disabled ? -1 : undefined}
|
||||
className={composedClassName}
|
||||
>
|
||||
{content}
|
||||
</Link>
|
||||
const isIconOnly = Icon != null && !label;
|
||||
const resolvedVariant = resolveVariant(type, variant);
|
||||
const composedClassName = [
|
||||
TYPE_CLASS[type],
|
||||
VARIANT_CLASS[resolvedVariant],
|
||||
isIconOnly ? ICON_ONLY_SIZE_CLASS[size] : SIZE_CLASS[size],
|
||||
Icon && label ? 'gap-1.5' : '',
|
||||
disabled ? 'pointer-events-none cursor-not-allowed opacity-45 saturate-50' : '',
|
||||
className,
|
||||
]
|
||||
.join(' ')
|
||||
.trim();
|
||||
const computedAriaLabel = ariaLabel ?? label;
|
||||
const iconClass = `${isIconOnly ? ICON_ONLY_CLASS[size] : ICON_CLASS[size]} shrink-0`;
|
||||
const content = (
|
||||
<>
|
||||
{Icon ? <Icon className={iconClass} aria-hidden="true" /> : null}
|
||||
{label ?? null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
type={htmlType}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
aria-label={computedAriaLabel}
|
||||
className={composedClassName}
|
||||
>
|
||||
{content}
|
||||
</button>
|
||||
);
|
||||
const handleLinkClick: MouseEventHandler<HTMLElement> = (event) => {
|
||||
if (disabled) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
onClick?.(event);
|
||||
};
|
||||
|
||||
if (to) {
|
||||
return (
|
||||
<Link
|
||||
to={to}
|
||||
onClick={handleLinkClick}
|
||||
aria-disabled={disabled}
|
||||
aria-label={computedAriaLabel}
|
||||
tabIndex={disabled ? -1 : undefined}
|
||||
className={composedClassName}
|
||||
>
|
||||
{content}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
type={htmlType}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
aria-label={computedAriaLabel}
|
||||
className={composedClassName}
|
||||
>
|
||||
{content}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user