DrawMap: Button, 부모 요소에 이미지 및 글자 사이즈 맞추기

UMC 동아리의 여름방학 프로젝트가 시작되었다. 프로젝트의 이름은 DrawMap이다. 상세한 설명은 나중에 따로 정리하고..
프로젝트를 시작하면서 일단 내가 맡은 부분은 버튼 컴포넌트를 제작하는 것이다.
버튼은 다양한 종류가 존재하는데 나는 크게 두개로 나뉘었다. Button 과 ButtonSelct. Button은 단순 클릭만 하는 버튼이라면 ButtonSelect는 말 그대로 Select, 드롭다운해서 항목을 선택하는 버튼이다. ButtonSelect는 추가 디자인이 필요해서 일단 미뤄두고, 해당 글은 Button 컴포넌트에 관한 글이다.

Button 컴포넌트 설명


Button 컴포넌트의 props는 일단 3가지로 type, img, content이다.
img는 이름 그대로 이미지를 넣는 부분이다.
content는 버튼이 이미지가 아닌 글자를 담고 있는 버튼이거나, 클릭하거나 hover하면 이미지였던 버튼이 글자를 담고 있는 버튼으로 바뀔 때 나타나야 할 버튼 글자를 담는다.
type은 버튼의 종류는 작성하는 부분이다. 버튼의 종류는 default, arrow, text-btn, more, text-more, acting이 있다.

drawmap 버튼 종류1

  • more

    이미지의 가장 상단의 버튼으로, default 버튼보다 사이즈가 작기 때문에 따로 분류하였다.

  • default

    모든 버튼의 기본이 되는 버튼이다. 따로 type을 지정해주지 않아도 될 것 같긴 하지만, 버튼을 사용할 때 확실하기 분류해주기 위해서 default라는 type명을 부여했다.

  • acting

    default 버튼에서 hover나 click시 이미지였던 버튼이 글자로 변경되는 버튼이다. 해당 버튼때문에 따로 span 태그를 추가하여 style로 값이 들어오지 않는다면 display:none을 해줬다.

drawmap 버튼 종류2

  • text-btn

    버튼의 내용이 글자만 존재하는 버튼이다. 이미지는 들어오지 않기 때문에 img 태그의 style에 img가 들어오지 않는다면 display:none으로 변경되도록 해줬다. 이걸 해주지 않는다면 해당 버튼을 사용할 때 이미지 alt가 보이게 된다.

  • ButtonSelect

    Select 버튼인데 추후 따로 컴포넌트를 만들어서 제작할 예정

  • arrow

    이미지가 화살표일 때, 해당 타입의 버튼을 사용해준다. default와 more 버튼과는 이미지 사이즈가 약간 다르기 때문에 따로 정의해줬다.

  • text-more

    해당 버튼은 text-btn과 다르게 사이즈가 굉장히 작기 때문에, 따로 정의해줬다.

auto와 max-content 설명


버튼 사이즈에 맞춰서 사용할 이미지의 사이즈가 자동으로 조절되도록 코드를 짜고 싶었다. 최대한.. 코드를 줄이고 싶었달까…
서칭의 서칭 끝에 다음과 같이 아주 좋은 방법을 찾아냈다.

  • width: auto;

    width 속성을 명시하지 않으면 auto가 기본값으로 사용이 된다.
    100%가 기본값이 아니다..

    auto를 사용하면 브라우저가 해당 요소의 width 속성값을 자동으로 계산해준다. 부모 요소로 부터 주어진 가용 너비에서 좌우 margin 크기를 제외한 너비를 width 값으로 사용한다.

  • width: max-content

    요소의 너비를 최대한 늘이고 싶을 때 사용한다. 최대 너비 역시 해당 요소가 담고 있는 컨텐츠에 의해 변경된다.

부모 요소에 이미지 사이즈 자동 맞추기


css 코드 이미지 2

부모 요소의 width가 존재해도 이미지 width와 height가 있기 때문에 대부분 부모 박스 밖으로 튀어나온다.

그렇기에 해결 방법(?)은 다음과 같다.
부모요소에 width를 주고 img에 width:100%를 주면 부모 요소의 너비의 100%를 차지하게 된다. 그리고 height:auto를 주면 원래 이미지가 가지고 있던 비율에 맞춰서 자동으로 높이가 조절된다!

글자 내용(컨텐츠)에 따라 버튼 사이즈 자동 조절


css 코드 이미지 1

text-btn(이미지에서는, level로 명시)의 경우에는 버튼 안의 내용이 글자이다. 이때, 버튼에 width를 한정시키게 되면 안의 컨텐츠가 버튼을 삐져나가거나 세로로 글자가 배열되거나.. 쨋든 이상하게 변한다.
해당 문제는 width를 max-content로 하면 해결된다. width: max-content로 하면 글자(컨텐츠)의 사이즈에 맞춰 자동으로 width가 조절된다!

마치며


새로운 프로젝트를 시작하게 되었는데, 어김없이 몰랐던 부분이 나타나고 그러다보면 새롭게 알게되는 내용이 많은 것 같다. 이래서 프로젝트는 꼭 해봐야 하는 것 같다.
그리고, 역시 효율적으로 살기 위해서 사람은 노력을 해야 하는 것 같다. 나중에 귀찮아지지 않기 Button 컴포넌트를 수정하지 않기 위해서 최대한 효율적으로 코드를 작성하려고 하는데 생각보다 쉽지 않다. 편히 살려면 그만큼 노력이 필요한게 맞다…

참고
부모 요소(element) 속 이미지 크기 맞추기
CSS의 width 속성과 너비 결정 매커니즘

UNIVE.US: radio와 input 스타일

input type='text' 값이 들어왔을 때, 배경색 변경하기


값이 들어왔을 떄, 배경색을 변경시켜주는 걸 css로 구현하기 위해서는 일단 input에 required 속성을 추가해야 한다. 값으로 required를 넣어, required="required"를 input 태그 안에 추가한다.
글을 작성하다가, required="required"의 내용은 안 나와서.. 그냥 required를 작성하면 동작하지 않을까? 라는 의문이 들어서 테스트를 해본 결과 그냥 required를 작성해도 잘 작동된다…!

input text 코드

해당 속성을 추가하고 css는 input:valid일시, 즉 input에 값이 들어있을 때 배경색상을 흰색으로 변경하게 한다.

text valid css

🚨주의🚨
input에 required 속성을 추가하지 않으면, 값을 입력했다가 다시 모든 값을 지우고 focus를 해제했을 때, 배경색상이 회색(값이 없을 때)으로 변경되지 않고 흰색(값이 있을 때)으로 유지된다.

input type='radio' 값을 checked 했을 때, label 색상 변경하기


radio를 checked 했을 때, radio와 연결된 label의 색상을 변경시켜주기 위한 코드(css)는 다음과 같다.

input:checked + label {
	color: red;
}

input이 checked 되었을 때, 인접 형제 요소인 label의 color를 변경하는 css 코드이다.
그런데, 해당 코드를 작성하면 스타일이 적용되지 않는 문제가 발생했다. 나의 html 코드는 다음과 같았다.

<div>
	<label>라디오와 연결된 라벨</label>
	<input type="radio" />
</div>

위와 같이, label이 먼저 오고 input이 그 다음에 오는 형태이다. 이 순서가 가장 큰 문제였다…

radio가 checked시, label에 스타일을 적용하기 위해서는 radio가 먼저 오고 label이 그 다음에 왔을 때만 css 코드가 작동했다.

Bard에 물어본 결과 다음과 같은 답을 받았다.

Bard 답변

그렇다고 한다… radio 앞에 label을 배치하게 되면 radio를 가리게 되어 작동하지 않는다고 한다..ㅜ
label을 앞에 했을 때, html은 잘 작동을 하는데 (label 클릭시, 연결된 radio가 체크되는) 스타일은 적용되지 않으니… 순서를 바꿔주기로 했다.

input radio 코드

순서를 변경해주니 css 코드가 잘 작동했다.

radio checked css

그리고, checked일 때, radio 버튼의 색상을 변경할 때 그냥 color로 하면 스타일이 적용되지 않았다. 서칭을 해보니 accent-color로 적용하면 색상이 잘 적용되었다.
accent-color는 UI 컨트롤의 색상을 변경시켜줄 때 사용한다고 한다.

구현영상

마무리


이번 기능들은 js가 아닌, css로도 충분히 가능할 것 같아서 css로 구현해보았다. css로 해서 금방 끝날 줄 알았는데… 생각보다 많은 난관에 봉착하여^^… 시간이 꽤 걸렸다. 역시, 코딩의 세계는 만만하지 않아…ㅜ

참고
CSS 선택자
label 태그
accent-color
checked

UNIVE.US: React-hook-form, 글자수세기 (onChange)

프로젝트를 진행하던중 textarea의 글자수를 세는 기능이 필요했다. 그래서 음~ 금방 끝나겠군 이라는 마음으로 빠르게 코드를 작성하였으나..? 문제가 생겨서 정말 ^^ 몇시간을 붙들었다..
그렇게.. 겨…우.. 해결할 수 있었다.

기존 코드


const [byte, setByte] = useState(0)
const countByte = (e) => {
  setByte(e.target.value.length);
}
...

<textarea
  ...
  onChange={countByte}
  {...register
  ...}
></textarea>
<span>{byte}/150</span>

기존 코드에서 react-hook-form을 사용해야 했고, textarea의 입력값이 필요했기에 onChange를 통해서 value값을 받아왔다.
근데 아무리 해도 값이 안 나오고…
그래서 서칭을 계속 했는데 나도 이런 문제인 줄 알고 currentTarget으로 바꿨으나 실패..

그렇게 같이 프로젝트를 하는 친구에게 코드를 봐달라고 했고.. 문제는 react-hook-form의 register이었다는 것을 알게되었다…

문제


react-hook-form에도 onChange가 존재하는데, 이게 우리가 가장 널리 알고 있는 일반 이벤트 핸들러의 onChange와 이름이 같기 때문에 충돌이 나는 것 같았다.. 흙..

따라서, react-hook-form의 onChange를 사용하여 코드를 변경하기로 했다.

해결 코드


register안에 onChange를 넣어 기존 코드에서 countByte 함수를 onChange에 바로 작성하였다. 이렇게 하니 기존코드보다 더욱 간결해졌다.

byte useState register onChange

구현 영상


글자수 세기 구현영상

마무리


해당 문제를 통해 아직 react-hook-form을 잘 모르고 있다는 것을 알게되었다… 더.. 많은 공부가 필요할 듯 하다..

참고
react hook form에서 form데이터 관리하기
입력을 다루는 다양한 방법, React-hook-form
stack overflow
Hook Form으로 상태 관리하기.

UNIVE.US: React, "\n" 개행적용 불가 해결

리액트에서만 이러는 건지는 모르겠지만, modal의 title 부분에 개행(‘\n’)을 적용하려 하는데 적용이 안됐다…

따라서 서칭끝에 해결 방법을 찾았다.

해결방법


div {
	white-space: pre-wrap;
}

바로 스타일을 통해서 개행이 작동하도록 해주는 것이다.
white-space는 공백문자를 처리하는 방법을 설정한다.
다양한 설정값이 존재하지만 나는 그 중에서도 개행을 해주는 것만 필요하기에 pre-wrap을 적용했다.

pre-wrap은 띄어쓰기, 들여쓰기, 줄바꿈을 그대로 적용시켜준다. 이러한 점은 pre 속성값과 동일한데, pre와 달리 pre-wrap은 텍스트 안에서 긴 행이 존재할 때 자동으로 줄바꿈을 적용시켜준다는 것이다. 따라서 좌우 스크롤바가 존재하지 않아도 그대로 화면에서 잘리지 않고 보이게 된다. (pre는 긴 행이 존재해도 그대로 출력한다.)

적용 결과 화면


1. white-space를 작성하지 않았을 때, 결과화면 => 개행적용 X

white-space 적용 안 한 modal 소스코드 white-space 적용안한 모달 소스코드

개행 추가 소스코드 개행있는 타이틀 소스코드

적용 결과 화면(개행 적용 안됨) 개행 안된 화면


2. white-space를 작성했을 때, 결과화면 => 개행 적용 O

white-space 적용한 modal 소스코드 white-space 적용한 모달 소스코드

개행 추가 소스코드 개행있는 타이틀 소스코드

적용 결과 화면(개행 적용 됨) 개행된 화면


3. white-space를 작성했지만, 개행을 작성하지 않았을 때, 결과화면 => 개행적용 X

white-space 적용한 modal 소스코드 white-space 적용한 모달 소스코드

개행 추가 없는 소스코드 개행없는 타이틀 소스코드

적용 결과 화면(개행 적용 안됨) 개행 안된 화면

결론


white-space를 추가해도 글에 개행(‘\n’)을 넣지 않으면 어엄청 긴 행이 아닌 이상 개행 적용이 안된다!

참고
html 또는 react에서 /r 또는 /n으로 줄바꿈(개행)이 안됨
CSS의 white-space 속성 사용법

UNIVE.US: React, 박스 숨기고 열기

유저 프로필 페이지에서, 타 유저를 신고하는 버튼이 존재한다.
버튼을 클릭하면 신고를 할 수 있는 modal이 나오며, 신고 사유는 checkbox로 중복 선택할 수 있다. 이때, ‘기타’를 선택할 경우 상세 신고 사유를 작성할 수 있는 박스가 생기는 기능이 필요했다.

‘기타’ checkbox를 클릭하면 상세 사유 작성란이 나타나고, 다시 checkbox를 해제하면 박스가 사라지도록 만드는 기능을 구현했다.

기타 박스 상태 관리


소스코드1

useState로 ‘기타’(앞으로 etc라고 작성하겠다.) 박스의 열고 닫힌 상태를 관리했다. 기본값은 false로 하여 닫혀있는 상태이다.

소스코드2

  • set(!etc)

    checkbox(input)를 클릭(onClick)하면 setEtc를 통해 상태가 변경된다.
    만약, etc의 값이 false(닫힌 상태)였다면 클릭을 통해 true(!etc/ 열린 상태)로 변경되고 값이 true였다면 false로 상태가 변화된다.

  • etc && (<textarea>...)

    또한, etc의 값이 true라면 <textarea>가 보이게 되며, false라면 textarea는 보이지 않게 된다.

구현 결과


박스 숨기기 화면 박스 열기 화면

위의 이미지와 같이 열고 숨기는 기능이 잘 구현된 것을 확인 할 수 있다.

마무리


이 간단한 기능조차 서칭을 통해 다른 분의 코드를 참고하고 작성하게 되었다. 일단 누군가의 코드를 참고해서 구현을 해낼 수 있다는 점에서 많이 성장했지만, 내가 생각하기에는 바닐라 js로 실제 개발한 경험이 매우 적다(거의 없다 싶이..)보니 스스로 떠올리는 것에 어려움이 존재한다는 것을 깨달았다.
일단은 다른 분의 코드를 참고함으로 어떻게 구현할 수 있을지 이번처럼 학습을 하여 나의 코드로 만들어 나가야 겠다.

참고
리액트: 버튼 클릭시 요소 표시, 숨기기