-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCircleButton.tsx
More file actions
127 lines (112 loc) · 3.29 KB
/
Copy pathCircleButton.tsx
File metadata and controls
127 lines (112 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { CaretUp, Warning } from '@phosphor-icons/react';
import { useEffect, useState } from 'react';
type ButtonVariant = 'default' | 'warning' | 'cancel';
export interface CircleButtonProps {
children?: JSX.Element | JSX.Element[];
variant?: ButtonVariant;
active?: boolean;
onClick?: () => void;
onClickToggleButton?: () => void;
className?: string;
dropdown?: React.ReactNode;
indicator?: {
icon?: JSX.Element;
className?: string;
};
}
const CircleButton = ({
children,
variant = 'default',
active = false,
onClick,
onClickToggleButton,
className = '',
dropdown,
indicator,
}: CircleButtonProps): JSX.Element => {
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (isOpen) {
const target = event.target as HTMLElement;
const circleButton = document.querySelector(`[data-circle-button="${variant}"]`);
if (circleButton && !circleButton.contains(target)) {
setIsOpen(false);
}
}
};
document.addEventListener('click', handleClickOutside);
return () => {
document.removeEventListener('click', handleClickOutside);
};
}, [isOpen, variant]);
const handleToggle = (e: React.MouseEvent) => {
e.stopPropagation();
if (dropdown) {
onClickToggleButton?.();
setIsOpen(!isOpen);
}
};
const handleMainClick = () => {
onClick?.();
};
const getButtonStyles = () => {
switch (variant) {
case 'cancel':
return 'bg-red hover:bg-red/85';
case 'warning':
return active ? 'bg-white/85' : 'bg-white/25 hover:bg-white/35';
default:
return active ? 'bg-white/85' : 'bg-white/25 hover:bg-white/35';
}
};
const renderIndicator = () => {
if (!indicator) return null;
if (variant === 'warning') {
return (
<div className="absolute -top-1 -right-1 h-5 w-5 bg-orange border border-black/35 rounded-full flex items-center justify-center">
<Warning size={12} color="black" weight="bold" />
</div>
);
}
return (
<div
className={`absolute -top-1 -right-1 h-5 w-5 flex items-center justify-center rounded-full ${indicator.className || ''}`}
>
{indicator.icon}
</div>
);
};
const renderDropdownButton = () => {
if (!dropdown || variant === 'cancel' || variant === 'warning') return null;
return (
<button
onClick={handleToggle}
className="absolute -top-1 -right-1 h-5 w-5 border bg-white border-black/35 rounded-full flex items-center justify-center hover:bg-gray-50"
>
<CaretUp size={10} color="black" weight="fill" />
</button>
);
};
return (
<div className="relative w-11 h-11" data-circle-button={variant}>
<button
onClick={handleMainClick}
className={`
h-11 w-11
flex items-center justify-center
rounded-full
transition-all duration-200
${getButtonStyles()}
${className}
`}
>
{children}
</button>
{renderDropdownButton()}
{renderIndicator()}
{isOpen && dropdown && variant !== 'cancel' && <div className="absolute bottom-full mb-2 left-0">{dropdown}</div>}
</div>
);
};
export default CircleButton;