사용자가 글을 입력할 수 있는 컴포넌트를 만들려면 보통 input이나 textarea를 활용한다.
디자이너님께서 새로 메모장 디자인을 전달해주셨는데,
글이 한 줄일 때는 뒤의 회색 배경이 글자와 딱 맞게 입력해야할 때마다 따라와야 하지만,
두 줄 이상일 때부터는 배경이 메모장의 최대 width로 유지되면서 줄 수 만큼 height가 늘어나야했다.
처음에는 textarea를 활용해보았는데, 뒤의 회색 배경이 글자를 따라오게 만드는데 실패했다 (fit-content 속성을 주었음에도 불구하고)
그 다음에는 input을 활용해보았는데, 뒤의 회색 배경이 글자를 따라오긴 하였지만, 글이 두 줄일 때 뒤의 회색 배경이 다음 줄로 넘어가지 않았다.
그래서 div에 contentEditable 속성을 주어 원하는 동작을 구현할 수 있었다. 그렇다면 어떻게 배경이 따라오는 메모장을 만들었는지 살펴보자.
<MemoContainer className="memo-container" onClick={handleMemoClick}>
<img src={이미지 주소} alt="메모" />
{isWriteMemo ? (
<span className="memo-text editing">
<EditableDiv
className={!memo ? "empty" : ""}
ref={editableDivRef}
contentEditable
onBlur={handleMemoBlur}
onKeyDown={handleKeyDown}
onInput={handleInput}
suppressContentEditableWarning={true}
></EditableDiv>
</span>
) : (
<span className="memo-text">{memo || "메모작성"}</span>
)}
</MemoContainer>
MemoContainer는 메모 컨테이너 전체의 레이아웃이고, EditableDiv는 실제 편집 가능한 텍스트 영역의 스타일이다.
EditableDiv의 속성 중에 suppressContentEditableWarning = {true}가 있는데, 이 속성이 없으면 콘솔에 수정이 가능한 요소 내에 react에서 관리하는 children도 포함되어 있기에 조심해달라는 warning이 뜨게 된다.
(자세한 내용은 이 링크를 참고하자 https://guiyomi.tistory.com/147 )
.memo-text {
width: auto;
max-width: 282px;
white-space: pre-wrap;
word-wrap: break-word;
overflow-wrap: break-word;
min-height: 21px;
display: inline-block;
&.editing {
background: transparent;
color: #202020;
position: relative;
z-index: 1;
padding-left: 6px;
// 배경 확장을 위한 가상 요소
&::before {
content: "";
position: absolute;
top: -4px;
left: 0;
right: -6px;
bottom: -4px;
background: #f0f0f0;
border-radius: 6px;
z-index: -1;
}
}
}
memo-text의 width는 auto이므로 글씨가 써질 때마다 늘어난다.
그 뒤의 회색 배경은 before로 만들었는데, editing의 position이 relative이므로 부모인 memo-text의 width를 따라간다. (가상 요소의 z-index는 -1를 줘서 뒤로 가게 만들었다)
또한 편집 모드로 들어갈 때 ‘메모를 입력하세요’ placeholder를 위치시키기 위해 가상 요소를 활용했다.
&:empty:before,
&.empty:empty:before {
content: "메모를 작성하세요";
color: #c4c4c4;
(...)
}
- &:empty:before - div가 완전히 비어있을 때
- &.empty:empty:before - div가 비어있고 empty 클래스가 있을 때
이렇게 두가지 방식을 처리했다.
'Intern' 카테고리의 다른 글
useRef를 활용하여 stale closure를 해결해보자 (0) | 2025.05.17 |
---|---|
모노레포에서 다른 프로젝트로 파일을 옮길 때 조심해야 할 점 (0) | 2025.04.19 |
네이버 지도 api 사용 시 마커가 많을 때 최적화 후기 (1) | 2025.03.15 |