Repository navigation
[fix] 앱 웹뷰에서 본문 텍스트를 선택·복사할 수 있게 한다 - #2257
seongwon030 wants to merge 3 commits into
Conversation
- body에 건 user-select: none이 상속돼 앱 웹뷰의 모든 본문 텍스트 선택이 막혀 있었다 - 선택 차단과 길게 누르기 메뉴 차단을 button, a, [role='button'], img에만 건다
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 52 minutes. View limit details
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
선택 차단 대상 변경 frontend/src/styles/WebviewGlobal.styles.ts |
user-select, -webkit-user-select, -webkit-touch-callout 선언을 body에서 button, [role='button'], img로 옮겼습니다. a는 새 선택자에 포함되지 않았습니다. |
Priority:
Estimated code review effort: 1 (Trivial) | ~3 minutes
Change: Bug fix · Severity of issue fixed: Medium
Suggested reviewers: oesnuj
Merge Risk: 
Low · previous review e9ef7
-
Some social-link controls may become selectable in app webviews, exposing link-selection menus during long press. Scope the exemption to prose links before merging.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passed-
Full details: Title check
-
Explanation
PR 제목은 앱 웹뷰에서 본문 텍스트를 선택하고 복사할 수 있도록 바꾸는 주요 변경과 일치합니다. 변경 내용은 WebviewGlobal.styles.ts에서 user-select와 -webkit-touch-callout 선언을 body에서 button, [role='button'], img로 옮기는 것입니다. 이 방식으로 본문 텍스트는 선택 가능해지고 버튼과 이미지는 보호됩니다. 목표 이슈와 커밋 메시지에 따르면 최종 선택자 범위에서 a는 제외되었습니다. 제목은 이 세부 범위를 다루지 않지만, 주요 변경 의도는 정확히 반영합니다.
Full details: Out of Scope Changes check
-
Explanation
이 PR의 변경은 frontend/src/styles/WebviewGlobal.styles.ts 의 CSS 선언 이동(+3/-1)으로 확인된다. 변경 내용은 body의 user-select, -webkit-user-select, -webkit-touch-callout을 button, [role='button'], img로 옮기고 cursor: default는 body에 남기는 것이다. 이는
#2256의요구(본문 선택 허용, 컨트롤 선택 차단)와 직접 연결된다. 웹(비웹뷰) 스타일이나 다른 컴포넌트 파일 변경은 확인되지 않았다. 다른 파일 변경 여부는 whole-PR 파일 목록 전체를 읽지 않아 완전히 확인하지는 못했다. 그러나 PR 요약에 해당 파일만 언급되어 있다.
Full details: Docstring Coverage
-
Explanation
No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 1 files.
-
Full details: Linked Issues check
-
Explanation
[
#2256] 요구사항: body의 user-select·-webkit-touch-callout을 button, a, [role='button'], img로 옮긴다. 확인된 변경(frontend/src/styles/WebviewGlobal.styles.ts, base 대비 head): body에서 두 선언을 제거했고, button, [role='button'], img 선택자에 추가했다. a 선택자는 없다. 따라서 명시된 선택자 목록 중 a가 빠졌다. 핵심 목표인 본문 선택 허용과 버튼·이미지 선택 차단은 구현되어 있다. PR 설명의 Playwright 결과(본문 선택 '탐험하는', 버튼 선택 없음, body user-select auto)는 이 PR의 설명에 기록된 결과다. 이 결과는 실행 환경에서 직접 재현하지 않았다. a를 뺀 이유는 linkifyText가 만든 인라인 링크 URL이 복사되지 않기 때문이다. 이 이유는 PR 설명과 커밋 메시지에 기록되어 있고, 첫 커밋 결과(URL 누락)가 근거다. 그러나 이슈 본문의 체크리스트는 a 포함을 요구하며 아직 수정되지 않았다. 따라서 요구사항과 구현이 일치하지 않는다.Resolution
둘 중 하나를 맞춘다. (1) 이슈
#2256의체크리스트와 선택자 목록을 갱신해 a 제외를 명시한다. 갱신 근거는 인라인 링크 URL 복사 불가 문제이다. (2) 구현을 이슈 요구대로 a를 포함하도록 바꾸고, 본문 링크 영역에 user-select: text 등 예외를 따로 적용해 URL 복사가 되도록 한다. 두 경우 모두 앱 UA에서 본문 링크 URL 복사와 버튼 선택 차단을 전후로 다시 확인한다.
-
Finishing Touches
-
📝 Generate docstrings
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
|
Claude finished @seongwon030's task in 32s —— View job harry 리뷰 총평
선택 차단을 다만 셀렉터에 그 밖에 harry 기준(색상 토큰, 폴더 구조, 주석, 보안)에 걸리는 부분은 없어요. 이 스타일을 덮는 테스트가 없다는 점은 PR 본문에 이미 적혀 있어서 따로 지적하지 않았어요. |
🎨 UI 변경사항을 확인해주세요
3개 스토리 변경 · 전체 193개 스토리 · 67개 컴포넌트 |
| -webkit-text-size-adjust: 100%; | ||
| cursor: default; | ||
| } | ||
| button, a, [role='button'], img { |
There was a problem hiding this comment.
a까지 막으면 본문 안의 URL은 이번 수정 후에도 복사할 수 없어요.
ClubIntroContent의 활동 소개·인재상·혜택·FAQ 답변은 linkifyText(@/utils/linkifyText.tsx)를 거쳐서 본문 속 https://...가 인라인 <a>로 렌더돼요. 동아리들이 오픈채팅·구글폼 주소를 여기에 적는 경우가 많은데, 이 셀렉터 때문에 다음 문제가 생겨요.
- 링크 텍스트만 길게 눌러 선택할 수 없어요.
- 문단을 통째로 잡아 복사해도 WebKit은
user-select: none구간을 빼고 복사해서 URL만 빠질 수 있어요. -webkit-touch-callout: none때문에 iOS의 "링크 복사" 메뉴도 막혀요.
PR이 풀려는 "연락처를 길게 눌러 복사" 시나리오에 정확히 걸리는 부분이라, a는 전역 셀렉터에서 빼는 게 좋아요. 카드처럼 쓰이는 링크(예: SocialLinkItem)에서 선택이 거슬리면 그 컴포넌트 스타일에 따로 거는 편이 안전해요.
| button, a, [role='button'], img { | |
| button, [role='button'], img { |
PR 검증 표에도 본문 URL 케이스(링크가 포함된 소개 문단)를 한 줄 추가해 주세요.
There was a problem hiding this comment.
맞아요, a를 셀렉터에서 뺐어요. e9ef711
linkifyText와 같은 마크업의 문단을 동아리 상세에 넣고 전체를 선택해 비교했더니, a를 막았을 때는 복사 결과가 "오픈채팅 로 문의"로 URL이 빠졌고, 지금은 URL까지 복사돼요. PR 본문 검증 절에 표로 추가했어요. MenuPage처럼 컨트롤로 쓰는 링크는 거슬리면 그 컴포넌트에 따로 걸게요.
- linkifyText가 소개·FAQ 본문의 URL을 인라인 <a>로 렌더해서, a에 건 user-select: none 때문에 문단을 복사하면 URL만 빠지고 iOS 링크 복사 메뉴도 막혔다
| -webkit-text-size-adjust: 100%; | ||
| cursor: default; | ||
| } | ||
| button, [role='button'], img { |
There was a problem hiding this comment.
[변경 범위] 커밋 의도는 "본문 속 링크"를 선택 가능하게 하는 건데, a를 전역 셀렉터에서 빼면 웹뷰 안의 모든 <a>가 같이 풀려요. MenuPage의 InfoLink(styled(Link)), RecommendedClubs의 Tag, ClubProfileCard의 SocialLinkItem처럼 버튼·행 역할을 하는 링크도 이제 길게 누르면 텍스트 선택이 잡히고, iOS에서는 -webkit-touch-callout까지 풀려 링크 미리보기/복사 메뉴가 떠요. 이전 커밋에서 "컨트롤은 막는다"던 기준과도 어긋나고요.
본문 링크만 풀고 싶다면 전역에서는 a를 유지하고, 본문 컨테이너 쪽에서만 해제하는 게 좁고 안전해 보여요. 예를 들면:
/* 전역 */
button, a, [role='button'], img { user-select: none; ... }
/* 본문 렌더 영역 스타일 */
.description a { user-select: text; -webkit-user-select: text; -webkit-touch-callout: default; }아니면 UI용 링크 쪽에 개별로 user-select: none을 붙이는 방법도 있어요. 메뉴 행·태그 같은 링크를 앱 웹뷰에서 길게 눌러 봤는지 한 번 확인해 주세요.
There was a problem hiding this comment.
반영했어요(41f9283). 다만 전역에 a를 다시 거는 대신, 컨트롤 링크를 컴포넌트에서 막는 쪽으로 갔어요.
두 방식 모두 새 화면에서 빠뜨릴 수 있는데, 빠뜨렸을 때 결과가 달라요. 전역 a를 막고 본문만 풀면, 본문 링크를 하나 빠뜨렸을 때 URL 복사가 안 되는 이번 버그가 그대로 돌아와요(linkifyText 말고도 LetterDetailPage의 react-markdown 링크가 있어요). 반대로 컨트롤 링크를 빠뜨리면 길게 눌렀을 때 글자가 선택되는 정도라 덜 해롭다고 봤어요.
- 막음:
MenuPageInfoLink,RecommendedClubsTag. 앱 UA로/menu에서InfoLink선택이 9자 → 0자가 되는 걸 확인했어요. - 안 막음:
SocialLinkItem. 안에 SNS 아이디(displayName)가 보여서 복사할 수 있어야 해요. - 나머지 컨트롤 링크(
PositionCard·BackLink·PolicyLink·SnsLink·ContactButton)는 실기기에서 길게 눌러 보지 못했어요. 거슬리는 곳만 후속으로 막을게요. PR 본문 영향 범위에 적어 뒀어요.
- 전역 셀렉터에서 a를 빼면서 행·태그처럼 버튼 역할을 하는 링크도 길게 누르면 텍스트가 선택되고 iOS 링크 메뉴가 떴다 - MenuPage InfoLink와 RecommendedClubs Tag에만 user-select·touch-callout 차단을 건다
| user-select: none; | ||
| -webkit-user-select: none; | ||
| -webkit-touch-callout: none; |
There was a problem hiding this comment.
[같이 수정되는 코드 함께 두기] 같은 세 줄(user-select·-webkit-user-select·-webkit-touch-callout)이 이번 커밋에서 RecommendedClubs.styles.ts의 Tag에도 똑같이 들어갔고, WebviewGlobal.styles.ts·LongPressReorderItem.styles.ts에도 이미 있어요. 나중에 -webkit-tap-highlight-color 같은 속성을 하나 더 넣어야 할 때 한 곳만 고치고 나머지를 빠뜨리기 쉬워요. @/styles에 noSelectOnLongPress 같은 이름의 css 조각으로 빼서 같이 쓰는 걸 생각해 보면 좋겠어요.
그리고 이 세 줄은 앱 웹뷰에서 길게 눌러도 링크가 선택되지 않게 하려는 거라, 코드만 봐서는 이유가 보이지 않아요. "본문 링크와 달리 메뉴 행은 길게 눌러도 선택되지 않게 한다" 정도로 한 줄 주석을 달아 두면, 나중에 누가 a 선택 차단을 다시 손볼 때 왜 여기만 따로 막았는지 알 수 있어요. 지금 이 스타일은 웹뷰가 아닌 일반 웹에도 적용된다는 점도 같이 확인해 주세요.
Close #2256
문제
앱 웹뷰에서 동아리 소개·연락처 같은 본문을 길게 눌러 복사할 수 없다.
WebviewGlobal.styles.ts가body에user-select: none을 걸어서 상속으로 페이지의 모든 텍스트 선택이 막힌다. 원래는/webview/*화면에서 컨트롤을 길게 눌렀을 때 선택되거나 메뉴가 뜨는 걸 막으려던 스타일(1900a7a38)이다. 그런데 지금은App.tsx에서 앱 웹뷰 전체에 적용된다.해결
선택 차단(
user-select)과 길게 누르기 메뉴 차단(-webkit-touch-callout)을body에서 빼고button, [role='button'], img에만 건다.a는 넣지 않는다.linkifyText가 소개·FAQ 본문의 URL을 인라인<a>로 렌더해서,a를 막으면 오픈채팅·구글폼 주소를 복사할 수 없다. 컨트롤을 길게 눌러도 선택되지 않는 원래 의도는 그대로 두고, 본문만 선택할 수 있게 푼다. 웹(비웹뷰) 스타일은 건드리지 않았다.검증
Playwright(iPhone 13 에뮬, UA에
MoadongApp)로 동아리 상세 소개 탭을 열고 본문과 버튼을 더블클릭해 선택 결과를 전후로 비교했다.소개내용)user-select""""none"탐험하는"""auto본문 URL은 dev 데이터에 해당 동아리가 없어서,
linkifyText와 같은 마크업(<a target="_blank">가 든 문단)을 동아리 상세 페이지에 넣고 문단 전체를 선택해 비교했다.user-selecta포함(첫 커밋)"오픈채팅 로 문의"(URL 빠짐)nonea제외(현재)"오픈채팅 https://open.kakao.com/o/probe 로 문의"autotypecheck·prettier 통과. 이 스타일을 덮는 테스트는 없다영향 범위
앱 웹뷰에만 닿는다(
isInAppWebView()일 때만 주입). 학생·관리자 웹은 영향이 없다. 드래그 제스처가 있는SwipeableEventRow(관리자 캘린더)와BuskingPagepan은 자체 선택 차단이 없어서, 길게 누르면 안의 글자가 선택될 수 있다(실기기 미확인).LongPressReorderItem·PhotoModal·QuestionBuilder는 자체user-select: none이 있다. 컨트롤로 쓰는 링크는 전역에서 막지 않고 컴포넌트에서 막는다. 본문 링크를 빠뜨려 URL을 복사하지 못하는 쪽(기능 손실)보다, 컨트롤 링크를 빠뜨려 길게 눌렀을 때 글자가 선택되는 쪽(보기 문제)이 덜 해롭기 때문이다.MenuPageInfoLink(메뉴 행),RecommendedClubsTag(추천 동아리 태그). 앱 UA로/menu를 열어 확인했다(InfoLink선택 9자 → 0자)ClubProfileCardSocialLinkItem. 안에 SNS 아이디(displayName)가 보여서 복사할 수 있어야 한다RecruitPagePositionCard·BackLink,FooterPolicyLink,ClubUnionPageSnsLink,ContactButton2곳. 실기기에서 거슬리는 곳만 후속으로 막는다