Dev/React

공통 컴포넌트 아이콘버튼 만들기

rryu09 2024. 11. 17. 01:24

 

아이콘을 버튼으로 쓰는 공통컴포넌트

disable, hover, active, default 등의 상태를 가지고 각각의 색상이 다르다

small, big 의 사이즈도 가진다

outlined 는 border가 있고 나머지 type 두개는 border가 없다

 

그래서 총 세가지 부분으로 컴포넌트를 나누어서 봤는데

1. 버튼 크기

2. 타입별 버튼 배경색

3. 아이콘 색상

 

type SizeType = 'small' | 'big';
type IconBtnType = 'solid' | 'normal' | 'outlined';
type IconButtonProps = {
	type: IconBtnType;
	size: SizeType;
	disabled: boolean;
	Icon: ReactElement;
	onClick: () => void;
};

 

필요한 props로는 이런 것들을 받았다.

Icon을 ReactElement로 사용하는 곳에서 주입해 사용할 수 있도록 했다.

 

// 사이즈별 분기
	const buttonSizes: Record<SizeType, SerializedStyles> = {
		big: css`
			width: 4rem;
			height: 4rem;
		`,
		small: css`
			width: 3.2rem;
			height: 3.2rem;
		`,
	};

첫번째로 사이즈별 분기

 

	// 아이콘 배경 색상 및 테두리
	const getIconBtnStyles = (
		strokeColor: string,
		defaultBG: string,
		hoverBG: string,
		pressedBG: string,
		border: boolean
	) => {
		if (disabled) {
			if (type === 'solid')
				return css`
					background-color: ${color.Blue.Blue2};
				`;
			return css`
				${border &&
				css`
					box-sizing: border-box;

					border: solid 1px ${color.Grey.Grey3};
				`}
			`;
		}
		return css`
			background-color: ${defaultBG};

			${border &&
			css`
				box-sizing: border-box;

				border: solid 1px ${strokeColor};
			`}

			:hover {
				background-color: ${hoverBG};
			}

			:active {
				background-color: ${pressedBG};
			}
		`;
	};
	const buttonStyles: Record<IconBtnType, SerializedStyles> = {
		solid: getIconBtnStyles(color.Grey.White, color.Blue.Blue6, color.Blue.Blue7, color.Blue.Blue8, false),
		normal: getIconBtnStyles(color.Grey.Grey5, color.Grey.White, color.Grey.Grey2, color.Grey.Grey3, false),
		outlined: getIconBtnStyles(color.Grey.Grey4, color.Grey.White, color.Grey.Grey2, color.Grey.Grey3, true),
	};

두번째로 배경색인데, 이부분이 좀 복잡하다. disabled인 경우 hover, active 인 상태를 막아야 하고, solid과 outlined normal이 다르다.

그런데 Outlined와 Normal은 테두리 있없 차이도 있어서 분기문을 어떻게 깔끔하게 작성할 수 있을지 고민스러웠다.

일단 선, 기본배경색, 호버시배경색, 눌렸을 때 색, 보더 유무 정도를 받아서 css 를 돌려주는 함수를 만들어, solid, normal, outlined 일때 각각 다른 css 를 받도록 했다.

경우가 많고 더러워서 그냥 저기서 css를 박아뒀어도 괜찮았을 것 같다는 생각도 든다.

 

이렇게 설정하고 styled 컴포넌트 안에 넣어줬다.

 

마지막으로 가장 걱정스러운 아이콘 색상 부분이다. 

// 아이콘 색상 설정
	const getIconColor = () => {
		const iconColors = {
			solid: theme.color.Grey.White,
			normal: disabled ? theme.color.Grey.Grey4 : theme.color.Grey.Grey5,
			outlined: disabled ? theme.color.Grey.Grey4 : theme.color.Grey.Grey5,
		};
		return iconColors[type];
	};
	const ColoredIcon = cloneElement(Icon, { color: getIconColor() });

이렇게 아이콘 색상을 따로 분기해서 얻고,

Icon을 reactElement로 받고 있기 때문에 props를 추가하기 위해 cloneElement 를 사용하고 얻은 색상을 props로 넘겨줬다.

svg 특성상 모양이 다른 경우가 많고 stroke 가 currentColor로 설정되어있지 않은 경우도 많아서 해당 부분을 건드리고 싶진 않았는데, 인라인 스타일이 css 스타일 건드린 것보다 우선되기 때문에 css로 stroke, fill 등 설정을 건드려봐도 적용되지 않는 문제가 있다.

 

일단은 이 상태로 다양한 상태를 가진 아이콘 버튼을 제작했다. 

 

https://github.com/TEAM-DAWM/NUTSHELL-FE/pull/290

 

[FEAT] 공통 컴포넌트 아이콘버튼 퍼블리싱 by wrryu09 · Pull Request #290 · TEAM-DAWM/NUTSHELL-FE

작업 내용 🧑‍💻 공컴 아이콘 버튼 부분 제작했습니다 스토리북에 예시 아이콘 넣어뒀는데 icn_setting_어쩌고 이렇게 쓰여있는 형식 Screaming snake라고 린트에서 뭐라 해서... 수정하고 사용된 사

github.com

 

'Dev > React' 카테고리의 다른 글

공통 컴포넌트 컨트롤버튼 개발일지  (1) 2024.11.20
useTheme vs theme import  (1) 2024.11.18
Next.js 라우팅  (8) 2024.05.08