Skip to content

[OMF-342] 이미지 문항 핀치 줌 및 전체화면 뷰어 개선#163

Merged
78-artilleryman merged 1 commit into
mainfrom
feature/OMF-342
May 12, 2026
Merged

[OMF-342] 이미지 문항 핀치 줌 및 전체화면 뷰어 개선#163
78-artilleryman merged 1 commit into
mainfrom
feature/OMF-342

Conversation

@78-artilleryman
Copy link
Copy Markdown
Contributor

@78-artilleryman 78-artilleryman commented May 12, 2026

📌 주요 변경 사항

  • 이미지 문항 핀치 줌 및 전체화면 뷰어 개선

🔗 관련 이슈

Jira 링크: https://onsurvey.atlassian.net/browse/OMF-342

✅ 리뷰 요청 사항 (Need Review)

  • 🙂 크게 우려되는 사항은 없어요. 가볍게 리뷰 부탁드려요.

🎨 스크린샷 (선택)

Summary by CodeRabbit

릴리스 노트

  • 신기능

    • 설문 이미지 전체화면 모드에서 핀치 제스처를 통한 인터랙티브 확대/축소 기능 추가
    • 사용자 안내용 줌 및 이동 힌트 오버레이 추가
  • 스타일

    • 이미지 확대 버튼 디자인 개선

Review Change Stack

- 핀치 투 줌(pinch-to-zoom) 및 확대/축소 기능 추가
- 전체화면 모달 UI 개선 (배경색, 라운드, 닫기 버튼 스타일)
- 확대 전 힌트 오버레이 표시 후 핀치 시 자동 소멸
- 인라인 스타일을 Tailwind 클래스로 전환
@78-artilleryman 78-artilleryman requested a review from chldsbdud May 12, 2026 14:27
@78-artilleryman 78-artilleryman self-assigned this May 12, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'project', 'rules', 'files', 'ignore'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

SurveyImage 컴포넌트가 제스처 기반의 전체 화면 확대 기능을 추가했습니다. 핀치 줌 상태 관리, 터치 이벤트 핸들러, 동적 이미지 스케일 변환, 줌 힌트 오버레이 UI 요소가 구현되었으며, 전체 화면 버튼 스타일과 React 훅 의존성이 업데이트되었습니다.

Changes

전체 화면 핀치 줌 상호작용

Layer / File(s) Summary
줌 설정 및 훅 의존성
src/features/survey/components/SurveyImage.tsx
React import이 useCallback, useEffect, useRef, useState 훅을 포함하도록 확장되었습니다. 줌 범위를 설정하는 MIN_SCALE, MAX_SCALE 상수와 스케일 값을 제한하는 clamp 헬퍼 함수가 추가되었습니다.
전체 화면 줌 상태 및 터치 핸들러
src/features/survey/components/SurveyImage.tsx
전체 화면 줌 상태가 도입됨: scale, isPinching, showHint 플래그와 핀치 거리 추적을 위한 ref가 추가되었습니다. resetZoom, handleClose 및 터치 이벤트 핸들러(handleTouchStart, handleTouchMove, handleTouchEnd)가 핀치 제스처를 감지하고 스케일을 업데이트합니다. Effect는 전체 화면에서 기본 touchmove 스크롤을 방지하고 전체 화면 진입 시 힌트를 표시합니다.
버튼 및 스타일 변형 업데이트
src/features/survey/components/SurveyImage.tsx
확장 버튼 스타일이 스타일 상수 방식에서 유틸리티 클래스 기반 className으로 변경되었습니다. VARIANT_STYLES 내 square 변형 스타일 블록 구조가 조정되었습니다.
전체 화면 포탈 마크업 및 줌/힌트 오버레이
src/features/survey/components/SurveyImage.tsx
전체 화면 포탈 JSX가 재작성됨: 오버레이 컨테이너와 닫기 버튼 스타일이 업데이트되었습니다. 이미지 래퍼가 이제 ref와 터치 이벤트 핸들러를 수용합니다. 동적 transform: scale 이 적용되며 핀치 중에는 트랜지션이 비활성화됩니다. showHint 플래그가 true일 때 조건부 힌트 오버레이가 렌더링됩니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

✨Feat

Suggested reviewers

  • chldsbdud
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 PR의 주요 변경사항인 이미지 문항의 핀치 줌 및 전체화면 뷰어 개선을 명확하게 반영하고 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/OMF-342

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/features/survey/components/SurveyImage.tsx (2)

119-133: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

버튼 클릭 핸들러에 Sentry ui.click 스팬이 누락되었습니다.

전체 보기 진입 버튼(Line 122 onClick)과 닫기 버튼(Line 149 onClick=handleClose) 모두 UI 인터랙션 추적이 빠져 있습니다. 코딩 가이드라인에 따라 Sentry.startSpan({ op: 'ui.click', ... })로 감싸고, 필요한 컨텍스트는 span.setAttribute()로 첨부해 주세요. 더불어 파일 상단의 Sentry import도 추가가 필요합니다.

♻️ 제안 예시
+import * as Sentry from '@sentry/react';
 import { adaptive } from "@toss/tds-colors";
 				<button
 					type="button"
 					aria-label="이미지 크게 보기"
-					onClick={() => setIsFullscreen(true)}
+					onClick={() =>
+						Sentry.startSpan(
+							{ op: 'ui.click', name: 'SurveyImage open fullscreen' },
+							(span) => {
+								span?.setAttribute('variant', variant);
+								setIsFullscreen(true);
+							},
+						)
+					}
 					className="absolute bottom-2 right-2 ..."
-	const handleClose = useCallback(() => {
-		setIsFullscreen(false);
-		setShowHint(false);
-		resetZoom();
-	}, [resetZoom]);
+	const handleClose = useCallback(() => {
+		Sentry.startSpan(
+			{ op: 'ui.click', name: 'SurveyImage close fullscreen' },
+			(span) => {
+				span?.setAttribute('finalScale', scale);
+				setIsFullscreen(false);
+				setShowHint(false);
+				resetZoom();
+			},
+		);
+	}, [resetZoom, scale]);

As per coding guidelines: "In component action handlers, use Sentry.startSpan with op: 'ui.click' to create spans for button clicks and other UI interactions, and use span.setAttribute() to add metrics" and "Import Sentry using import * as Sentry from '@sentry/react'".

Also applies to: 146-164

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/survey/components/SurveyImage.tsx` around lines 119 - 133, Add
Sentry UI click spans around the fullscreen-enter and close button handlers in
SurveyImage.tsx: import Sentry with "import * as Sentry from '@sentry/react'" at
the top, then wrap the onClick that calls setIsFullscreen(true) (the inline
handler using setIsFullscreen) and the onClick that invokes handleClose in
Sentry.startSpan({ op: 'ui.click', description: '...'}), call
span.setAttribute(...) to attach relevant context (e.g., action:
'open_fullscreen' or 'close_fullscreen', imageId or src), and ensure you call
span.finish() after the handler completes (or in finally) so the span always
closes.

136-144: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

전체화면 모달에 키보드 닫기(Escape) 지원이 누락되었습니다.

role="dialog" + aria-modal="true"로 모달임을 명시했지만 키보드 사용자(예: 외장 키보드 연결 환경, 데스크톱 웹뷰)는 Escape로 닫을 수 없고, 포커스가 모달 외부에 머무를 수 있습니다. 최소한 Escape 키 핸들러를 추가하고, 가능하면 모달 진입 시 포커스를 닫기 버튼으로 이동시켜 주세요.

🛠️ 제안 패치
 	useEffect(() => {
 		if (!isFullscreen) return;
-		setShowHint(true);
-	}, [isFullscreen]);
+		setShowHint(true);
+		const onKeyDown = (e: KeyboardEvent) => {
+			if (e.key === "Escape") handleClose();
+		};
+		window.addEventListener("keydown", onKeyDown);
+		return () => window.removeEventListener("keydown", onKeyDown);
+	}, [isFullscreen, handleClose]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/survey/components/SurveyImage.tsx` around lines 136 - 144, Add
keyboard Escape support and initial focus for the fullscreen modal in the
SurveyImage component: create a ref (e.g., closeButtonRef) for the modal close
button and, inside a useEffect that runs when isFullscreen changes, if
isFullscreen and typeof document !== "undefined" focus closeButtonRef.current
and attach a keydown listener on document that calls the component's existing
close handler (e.g., closeFullscreen / onClose / toggleFullscreen — use the
exact function name used in this file) when event.key === "Escape"; remove the
listener and blur/cleanup on unmount or when isFullscreen becomes false. Ensure
the createPortal modal markup uses the referenced close button element so
focus-able action exists and that the effect only runs when isFullscreen is
true.
🧹 Nitpick comments (1)
src/features/survey/components/SurveyImage.tsx (1)

103-106: ⚡ Quick win

힌트가 사용자가 핀치하지 않으면 사라지지 않습니다.

showHint는 전체화면 진입 시 true로 설정되고, handleTouchStart에서 두 손가락 터치가 시작될 때만 false로 바뀝니다. 따라서 사용자가 한 손가락만 사용하거나 잠시 보기만 한 채로 머무르면 안내 오버레이가 계속 노출됩니다. 일정 시간 후 자동으로 숨기거나, 최초 터치(1손가락 포함) 시 숨기는 것이 자연스럽습니다.

♻️ 자동 사라짐 예시
 	useEffect(() => {
 		if (!isFullscreen) return;
-		setShowHint(true);
+		setShowHint(true);
+		const timer = window.setTimeout(() => setShowHint(false), 2500);
+		return () => window.clearTimeout(timer);
 	}, [isFullscreen]);

Also applies to: 189-203

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/survey/components/SurveyImage.tsx` around lines 103 - 106, The
hint overlay is set true on entering fullscreen (useEffect that sets showHint)
but only cleared on two-finger pinch in handleTouchStart, so it never hides for
single-finger touches or passive viewing; update the logic so showHint is
cleared either on the first touch of any type
(handleTouchStart/handlePointerDown) or after a short timeout (e.g., 3s) when
isFullscreen becomes true; modify the useEffect that sets showHint and the touch
handlers (handleTouchStart) to call the same hideHint routine (or start a timer)
and apply the same fix to the duplicate hint logic used elsewhere (the other
showHint/useEffect block around the second occurrence).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/survey/components/SurveyImage.tsx`:
- Around line 188-203: The hint text promises panning but the touch handler only
updates scale, so either implement pan or change the hint; to implement pan, add
translateX and translateY state in the SurveyImage component and update them
inside handleTouchMove when touches.length === 1 by computing clientX/clientY
deltas (store previous touch point to compute delta), then include
translate(...) together with scale(...) in the image style/transform;
alternatively, if you prefer the simpler fix, update the hint (showHint text) to
instruct only pinch-to-zoom (e.g., "두 손가락으로 확대해 보세요!") and ensure any duplicated
hint usages (the other hint at lines ~72-86) are changed consistently.
- Around line 72-86: In the SurveyImage component's touch handler, remove the
ineffective e.preventDefault() call from the useCallback function named
handleTouchMove; keep the two-finger distance calculation and scale update logic
(references: handleTouchMove, lastTouchDistRef, setScale, MIN_SCALE, MAX_SCALE)
unchanged, since native touchmove with passive:false (the addEventListener
handler) is already responsible for blocking scroll—just delete the
e.preventDefault() line to avoid relying on React's passive synthetic event
behavior.

---

Outside diff comments:
In `@src/features/survey/components/SurveyImage.tsx`:
- Around line 119-133: Add Sentry UI click spans around the fullscreen-enter and
close button handlers in SurveyImage.tsx: import Sentry with "import * as Sentry
from '@sentry/react'" at the top, then wrap the onClick that calls
setIsFullscreen(true) (the inline handler using setIsFullscreen) and the onClick
that invokes handleClose in Sentry.startSpan({ op: 'ui.click', description:
'...'}), call span.setAttribute(...) to attach relevant context (e.g., action:
'open_fullscreen' or 'close_fullscreen', imageId or src), and ensure you call
span.finish() after the handler completes (or in finally) so the span always
closes.
- Around line 136-144: Add keyboard Escape support and initial focus for the
fullscreen modal in the SurveyImage component: create a ref (e.g.,
closeButtonRef) for the modal close button and, inside a useEffect that runs
when isFullscreen changes, if isFullscreen and typeof document !== "undefined"
focus closeButtonRef.current and attach a keydown listener on document that
calls the component's existing close handler (e.g., closeFullscreen / onClose /
toggleFullscreen — use the exact function name used in this file) when event.key
=== "Escape"; remove the listener and blur/cleanup on unmount or when
isFullscreen becomes false. Ensure the createPortal modal markup uses the
referenced close button element so focus-able action exists and that the effect
only runs when isFullscreen is true.

---

Nitpick comments:
In `@src/features/survey/components/SurveyImage.tsx`:
- Around line 103-106: The hint overlay is set true on entering fullscreen
(useEffect that sets showHint) but only cleared on two-finger pinch in
handleTouchStart, so it never hides for single-finger touches or passive
viewing; update the logic so showHint is cleared either on the first touch of
any type (handleTouchStart/handlePointerDown) or after a short timeout (e.g.,
3s) when isFullscreen becomes true; modify the useEffect that sets showHint and
the touch handlers (handleTouchStart) to call the same hideHint routine (or
start a timer) and apply the same fix to the duplicate hint logic used elsewhere
(the other showHint/useEffect block around the second occurrence).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 300626c1-94ac-44f0-91c7-50f7a0fe0e00

📥 Commits

Reviewing files that changed from the base of the PR and between 2259fdb and f1b2fba.

📒 Files selected for processing (1)
  • src/features/survey/components/SurveyImage.tsx

Comment on lines +72 to +86
const handleTouchMove = useCallback((e: React.TouchEvent) => {
e.preventDefault();
if (e.touches.length === 2) {
const ddx = e.touches[0].clientX - e.touches[1].clientX;
const ddy = e.touches[0].clientY - e.touches[1].clientY;
const newDist = Math.sqrt(ddx * ddx + ddy * ddy);

if (lastTouchDistRef.current !== null) {
const ratio = newDist / lastTouchDistRef.current;
setScale((prev) => clamp(prev * ratio, MIN_SCALE, MAX_SCALE));
}

lastTouchDistRef.current = newDist;
}
}, []);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Are React 18 synthetic onTouchMove listeners passive at the root, making e.preventDefault() ineffective?

💡 Result:

Yes—React’s synthetic onTouchMove/onTouchStart/onWheel handlers are effectively registered as passive at the root in the common intervention case, so calling e.preventDefault inside those handlers will not prevent the default behavior. React explicitly describes this behavior: the “Keep onTouchStart, onTouchMove, and onWheel passive” change states that e.preventDefault in these handlers stays broken “due to Chrome’s intervention,” even though React moved from document-level listeners to root listeners [1]. The corresponding code change emulates passive listeners on roots for touchstart/touchmove/wheel (sets isPassiveListener = true for those event names) [2]. For React 18 specifically, community discussion confirms the intent and that there isn’t a React-native API to mark these listeners as non-passive; the issue notes that even onWheel/onTouchMove handlers “are passive” so preventDefault doesn’t work, and suggests manual addEventListener workarounds instead [3]. Related: React’s SyntheticEvent wrapper still exposes preventDefault [4], but whether it has effect is constrained by the browser’s passive listener semantics (the problem is at listener registration, not at the SyntheticEvent API surface) [1][2][4]. Workaround (if you truly need preventDefault): attach native listeners yourself with { passive: false } (for example via useEffect + addEventListener on the element), because React doesn’t provide an escape hatch for non-passive React synthetic touch/wheel handlers [3][5].

Citations:


🏁 Script executed:

# Check the full file content around the mentioned lines to verify the workaround
head -n 110 src/features/survey/components/SurveyImage.tsx | tail -n 40

Repository: On-Survey/Frontend

Length of output: 1174


React 합성 이벤트의 e.preventDefault()는 실제로 작동하지 않습니다.

React 18에서 onTouchMove 합성 이벤트 리스너는 루트에서 passive로 등록되므로, Line 73의 e.preventDefault() 호출은 스크롤을 차단하지 못합니다. 실제 스크롤 차단은 Lines 94–101의 네이티브 addEventListener("touchmove", ..., { passive: false })로 구현된 핸들러가 담당합니다. 합성 이벤트 핸들러에서 불필요한 e.preventDefault() 호출을 제거하세요.

♻️ 제안 패치
 	const handleTouchMove = useCallback((e: React.TouchEvent) => {
-		e.preventDefault();
 		if (e.touches.length === 2) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleTouchMove = useCallback((e: React.TouchEvent) => {
e.preventDefault();
if (e.touches.length === 2) {
const ddx = e.touches[0].clientX - e.touches[1].clientX;
const ddy = e.touches[0].clientY - e.touches[1].clientY;
const newDist = Math.sqrt(ddx * ddx + ddy * ddy);
if (lastTouchDistRef.current !== null) {
const ratio = newDist / lastTouchDistRef.current;
setScale((prev) => clamp(prev * ratio, MIN_SCALE, MAX_SCALE));
}
lastTouchDistRef.current = newDist;
}
}, []);
const handleTouchMove = useCallback((e: React.TouchEvent) => {
if (e.touches.length === 2) {
const ddx = e.touches[0].clientX - e.touches[1].clientX;
const ddy = e.touches[0].clientY - e.touches[1].clientY;
const newDist = Math.sqrt(ddx * ddx + ddy * ddy);
if (lastTouchDistRef.current !== null) {
const ratio = newDist / lastTouchDistRef.current;
setScale((prev) => clamp(prev * ratio, MIN_SCALE, MAX_SCALE));
}
lastTouchDistRef.current = newDist;
}
}, []);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/survey/components/SurveyImage.tsx` around lines 72 - 86, In the
SurveyImage component's touch handler, remove the ineffective e.preventDefault()
call from the useCallback function named handleTouchMove; keep the two-finger
distance calculation and scale update logic (references: handleTouchMove,
lastTouchDistRef, setScale, MIN_SCALE, MAX_SCALE) unchanged, since native
touchmove with passive:false (the addEventListener handler) is already
responsible for blocking scroll—just delete the e.preventDefault() line to avoid
relying on React's passive synthetic event behavior.

Comment on lines +188 to +203
{/* Hint */}
{showHint && (
<div className="absolute bottom-10 flex items-center gap-2 px-5 py-3 rounded-full pointer-events-none bg-[#B0B8C1]">
<Asset.Icon
frameShape={Asset.frameShape.CleanW24}
backgroundColor="transparent"
name="icon-x-mono"
color={adaptive.grey600}
name="icon-arrow-maximum-mono"
color="#ffffff"
aria-hidden={true}
ratio="1/1"
/>
</button>
</div>
<span className="text-white text-sm font-medium whitespace-nowrap">
확대하고, 손으로 움직여보세요!
</span>
</div>
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

힌트 문구와 실제 구현이 일치하지 않습니다.

힌트 오버레이의 문구는 "확대하고, 손으로 움직여보세요!"인데, handleTouchMove는 두 손가락의 거리(scale)만 갱신할 뿐 한 손가락 팬(pan/translate) 동작은 구현되어 있지 않습니다. 확대 후 이미지의 가려진 영역을 이동시킬 수단이 없어 사용자가 안내대로 시도해도 동작하지 않습니다.

다음 중 하나로 정렬해 주세요.

  • 팬(이동) 기능까지 구현 (예: translateX/Y 상태를 추가하고 touches.length === 1일 때 clientX/Y 델타로 갱신, transformtranslate(...) 합성).
  • 또는 팬을 구현하지 않을 경우 힌트 문구를 확대 동작만 안내하도록 수정 (예: "두 손가락으로 확대해 보세요!").

Also applies to: 72-86

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/survey/components/SurveyImage.tsx` around lines 188 - 203, The
hint text promises panning but the touch handler only updates scale, so either
implement pan or change the hint; to implement pan, add translateX and
translateY state in the SurveyImage component and update them inside
handleTouchMove when touches.length === 1 by computing clientX/clientY deltas
(store previous touch point to compute delta), then include translate(...)
together with scale(...) in the image style/transform; alternatively, if you
prefer the simpler fix, update the hint (showHint text) to instruct only
pinch-to-zoom (e.g., "두 손가락으로 확대해 보세요!") and ensure any duplicated hint usages
(the other hint at lines ~72-86) are changed consistently.

@78-artilleryman 78-artilleryman merged commit f8f2dfc into main May 12, 2026
5 checks passed
@78-artilleryman 78-artilleryman deleted the feature/OMF-342 branch May 12, 2026 14:31
@hkkang42
Copy link
Copy Markdown

흠...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants