Modal.jsx
export const ModalBackground = styled.div`
width: 100%;
height: 100vh;
inset: 0px;
position: fixed;
opacity: 0.8;
background-color: rgb(221, 221, 221);
`;
export const FisrtModal = styled.div`
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 12px;
box-sizing: border-box;
padding: 24px;
background-color: rgb(255, 255, 255);
width: 500px;
height: 300px;
position: absolute;
`;
export const SecondModal = styled.div`
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 12px;
box-sizing: border-box;
padding: 24px;
background-color: rgb(255, 255, 255);
width: 300px;
height: 200px;
position: absolute;
`;
App.js 에서 반환
const [modalOpen1, setModalOpen1] = useState(false);
const [modalOpen2, setModalOpen2] = useState(false);
const modalRef = useRef();
const showModal1 = () => {
setModalOpen1(true);
};
const showModal2 = () => {
setModalOpen2(true);
};
const closeModal = () => {
setModalOpen1(false);
};
const closeModa2 = () => {
setModalOpen2(false);
};
------------------------------------------------
<div id="modal">
{modalOpen1 && (
<div>
<ModalBackground />
<FisrtModal>
<div>
닫기와 확인 버튼 2개가 있고, 외부 영역을 눌러도 모달이 닫히지
않아요.
</div>
<ButtonMarginBox
style={{
position: "absolute",
bottom: "12px",
right: "12px",
}}
>
<SmallButton color="#d63031" onClick={closeModal}>
닫기
</SmallButton>
<SmallButton color="#000000">확인</SmallButton>
</ButtonMarginBox>
</FisrtModal>
</div>
)}
{modalOpen2 && (
<div ref={modalRef}>
<ModalBackground onClick={closeModa2} />
<SecondModal>
닫기 버튼 1개가 있고, <br />
외부 영역을 누르면 모달이 닫혀요.
<CloseButton onClick={closeModa2}>X</CloseButton>
</SecondModal>
</div>
)}
</div>
모달 상태를 관리해주는 것을 2개 선언하고 상태가 true일 때에만 보여주게 설정해주었다.
배경과 모달을 같은 구간에 두었기 때문에 이벤트 버블링이 일어나지 않아 바깥을 클릭하면 닫히게 된다.
물론 모달창을 클릭하면 닫히지 않는다.
Selects.jsx
export const Select = styled.button`
border: 1px solid rgb(221, 221, 221);
height: 40px;
width: 300px;
background-color: rgb(255, 255, 255);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0px 28px;
cursor: pointer;
`;
export const OptionList = styled.ul`
position: absolute;
top: 655px;
left: 18px;
z-index: 100px;
width: 290px;
background: rgb(255, 255, 255);
border: 1px solid rgb(221, 221, 221);
color: black;
list-style-type: none;
padding: 0;
border-radius: 6px;
align-items: center;
transition: 0.3s ease-in;
&:active {
max-height: 500px;
}
`;
export const DetailList = styled.li`
font-size: 12px;
padding: 10px;
&:hover {
background-color: #c0c0c0;
}
`;
App.js
const selectRef = useRef();
const handleClick = (event) => {
if (Boolean(selectRef.current) && event.target !== selectRef.current) {
hideSelect();
}
};
.
.
.
<SelectBox>
<h1>Select</h1>
<div
style={{
display: "flex",
gap: "10px",
}}
>
<div style={{ position: "relative" }}>
<Select onClick={showSelect}>
<div>{selectValue}</div>
<div>▼</div>
</Select>
</div>
<div style={{ position: "relative" }}>
<Select onClick={showSelect2}>
<div>{selectValue2}</div>
<div>▼</div>
</Select>
{selectState2 && (
<div>
<OptionList
style={{
top: "28px",
left: "6px",
}}
ref={selectRef}
>
<DetailList onClick={selectedValue2}>리액트</DetailList>
<DetailList onClick={selectedValue2}>자바</DetailList>
<DetailList onClick={selectedValue2}>스프링</DetailList>
<DetailList onClick={selectedValue2}>
리액트네이티브
</DetailList>
</OptionList>
</div>
)}
</div>
</div>
</SelectBox>
.
.
.
{selectState && (
<div>
<OptionList ref={selectRef}>
<DetailList onClick={selectedValue}>리액트</DetailList>
<DetailList onClick={selectedValue}>자바</DetailList>
<DetailList onClick={selectedValue}>스프링</DetailList>
<DetailList onClick={selectedValue}>리액트네이티브</DetailList>
</OptionList>
</div>
)}
모달과 동일하게 이벤트 처리를 해주었다. overflow: hidden;
으로 인해 두번째 select는 클릭하면 잘리게 보인다.
selectref가 true이면서, 외부를 클릭했을 때 hideSelect()가 동작하게 만든다.
handleClick을 메인 페이지에 이벤트를 등록해주고 토글목록이 보여져있고 토글 이외의 것을 클릭했을 때 이벤트동작이 이루어진다.
아이콘 사이트
1) React Icons
설치하고 import해서 스타일 컴포넌트로 적용하기만 하면 되기 때문에 사용하기 쉽다.
2) Font Awesome
overflow: hidden;
해당 구간 외로 나가면 안보이게 만들어준다.
태그가 어디에 위치하느냐에 따라 style이 변하거나 target이 가리키는 것이 다를 수 있다는 점을 인지하고 스타일링 해야한다.
시간이 될 때 readme를 정리하고 리팩토링을 하면 좋을 것 같다.