chore: initial commit
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { Button } from './button';
|
||||
|
||||
describe('Test Button Component', () => {
|
||||
it('renders the button with children text', () => {
|
||||
render(<Button>Click Me</Button>);
|
||||
expect(screen.getByText('Click Me')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onClick when clicked', async () => {
|
||||
const handleClick = vi.fn();
|
||||
render(<Button onClick={handleClick}>Click Me</Button>);
|
||||
|
||||
const user = userEvent.setup();
|
||||
await user.click(screen.getByText('Click Me'));
|
||||
|
||||
expect(handleClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('applies the correct variant class', () => {
|
||||
render(<Button variant="danger">Delete</Button>);
|
||||
|
||||
const button = screen.getByText('Delete');
|
||||
|
||||
expect(button).toHaveClass('bg-danger-500');
|
||||
expect(button).toHaveClass('hover:bg-danger-600');
|
||||
expect(button).toHaveClass('text-white');
|
||||
});
|
||||
|
||||
it("disables the button when 'disabled' prop is set", async () => {
|
||||
const handleClick = vi.fn();
|
||||
render(
|
||||
<Button variant="primary" disabled onClick={handleClick}>
|
||||
Disabled
|
||||
</Button>
|
||||
);
|
||||
|
||||
const user = userEvent.setup();
|
||||
const button = screen.getByText('Disabled');
|
||||
|
||||
expect(button).toBeDisabled();
|
||||
|
||||
await user.click(button);
|
||||
expect(handleClick).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import {
|
||||
FC,
|
||||
ReactElement,
|
||||
ButtonHTMLAttributes,
|
||||
DetailedHTMLProps,
|
||||
} from 'react';
|
||||
import { cn } from '@imphnen-frontend-service/utils';
|
||||
|
||||
type TButtonVariant =
|
||||
| 'primary'
|
||||
| 'secondary'
|
||||
| 'success'
|
||||
| 'danger'
|
||||
| 'text'
|
||||
| 'bordered';
|
||||
type TButtonSize = 'sm' | 'md' | 'lg';
|
||||
|
||||
type TButtonProps = DetailedHTMLProps<
|
||||
ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
HTMLButtonElement
|
||||
> & {
|
||||
variant?: TButtonVariant;
|
||||
size?: TButtonSize;
|
||||
};
|
||||
|
||||
const variantClasses: Record<TButtonVariant, string> = {
|
||||
primary: 'bg-primary-500 hover:bg-primary-600 text-white shadow-md',
|
||||
secondary:
|
||||
'bg-white hover:text-primary-600 hover:bg-gray-50 text-primary-500 shadow-md',
|
||||
text: 'bg-transparent hover:text-primary-600 hover:bg-gray-50 text-primary-500',
|
||||
bordered:
|
||||
'border border-primary-500 hover:border-primary-600 bg-transparent hover:text-primary-600 hover:bg-gray-50 text-primary-500',
|
||||
success: 'bg-success-500 hover:bg-success-600 text-white shadow-md',
|
||||
danger: 'bg-danger-500 hover:bg-danger-600 text-white shadow-md',
|
||||
};
|
||||
|
||||
const sizeClasses: Record<TButtonSize, string> = {
|
||||
sm: 'text-[12px] max-h-[36px]',
|
||||
md: 'text-[15px] max-h-[40px]',
|
||||
lg: 'text-[19px] max-h-[44px]',
|
||||
};
|
||||
|
||||
const disabledClass = 'opacity-50 cursor-not-allowed';
|
||||
|
||||
export const Button: FC<TButtonProps> = ({
|
||||
variant = 'primary',
|
||||
size = 'md',
|
||||
disabled,
|
||||
className,
|
||||
children,
|
||||
...rest
|
||||
}): ReactElement => {
|
||||
const mergedClassName = cn(
|
||||
'inline-flex items-center justify-center font-[600] rounded-lg px-[16px] py-[10px]',
|
||||
'transition-colors duration-200 cursor-pointer',
|
||||
sizeClasses[size],
|
||||
variantClasses[variant],
|
||||
disabled && disabledClass,
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<button className={mergedClassName} disabled={disabled} {...rest}>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './button';
|
||||
@@ -0,0 +1 @@
|
||||
export * from './button';
|
||||
Reference in New Issue
Block a user