From 302ab79dd41d8b1435974bb1fdcc698863488340 Mon Sep 17 00:00:00 2001 From: Jaybe Date: Sun, 16 Nov 2025 23:34:39 +0900 Subject: [PATCH] =?UTF-8?q?WYSIWYG:=20=ED=82=A4=EB=B3=B4=EB=93=9C=20nudge(?= =?UTF-8?q?Shift=201px=20=EB=B9=84=EC=8A=A4=EB=83=85,=20Alt=2016px=20?= =?UTF-8?q?=EC=8A=A4=EB=83=85)=20TDD/=EA=B5=AC=ED=98=84=20=EB=B0=8F=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/wysiwyg/Canvas.nudge.test.tsx | 27 ++++++++++++++++++++++++ components/wysiwyg/Canvas.tsx | 20 ++++++++++++------ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/components/wysiwyg/Canvas.nudge.test.tsx b/components/wysiwyg/Canvas.nudge.test.tsx index 4d91bee..6a9f2f0 100644 --- a/components/wysiwyg/Canvas.nudge.test.tsx +++ b/components/wysiwyg/Canvas.nudge.test.tsx @@ -41,4 +41,31 @@ describe('WYSIWYG Canvas keyboard nudge with 8px snap', () => { const obj = getByTestId('obj-o1') expect(obj).toHaveStyle({ top: '96px' }) // 100 - 1 => 99 -> snap8 => 96 }) + + it('Shift+ArrowRight nudges by 1px without grid snap', () => { + const frame = makeFrame() + const { getByTestId } = render() + const canvas = getByTestId('wysiwyg-canvas') + fireEvent.keyDown(canvas, { key: 'ArrowRight', shiftKey: true }) + const obj = getByTestId('obj-o1') + expect(obj).toHaveStyle({ left: '102px' }) // 101 + 1 => 102 (no snap) + }) + + it('Shift+ArrowUp nudges by 1px without grid snap', () => { + const frame = makeFrame() + const { getByTestId } = render() + const canvas = getByTestId('wysiwyg-canvas') + fireEvent.keyDown(canvas, { key: 'ArrowUp', shiftKey: true }) + const obj = getByTestId('obj-o1') + expect(obj).toHaveStyle({ top: '99px' }) // 100 - 1 => 99 (no snap) + }) + + it('Alt+ArrowRight nudges by 16px and snaps to grid', () => { + const frame = makeFrame() + const { getByTestId } = render() + const canvas = getByTestId('wysiwyg-canvas') + fireEvent.keyDown(canvas, { key: 'ArrowRight', altKey: true }) + const obj = getByTestId('obj-o1') + expect(obj).toHaveStyle({ left: '120px' }) // 101 + 16 = 117 -> snap8 => 120 + }) }) diff --git a/components/wysiwyg/Canvas.tsx b/components/wysiwyg/Canvas.tsx index fd97b35..32522e6 100644 --- a/components/wysiwyg/Canvas.tsx +++ b/components/wysiwyg/Canvas.tsx @@ -56,15 +56,23 @@ export function Canvas({ frame, onChange }: CanvasProps) { const onKeyDown = useCallback((e: React.KeyboardEvent) => { if (!selected) return let dx = 0, dy = 0 - if (e.key === 'ArrowLeft') dx = -1 - else if (e.key === 'ArrowRight') dx = 1 - else if (e.key === 'ArrowUp') dy = -1 - else if (e.key === 'ArrowDown') dy = 1 + let step = 1 + let useSnap = true + // Shift: 미세 이동(1px, 스냅 없음), Alt: 가속 이동(16px, 스냅 적용) + if (e.shiftKey) { step = 1; useSnap = false } + else if (e.altKey) { step = 16; useSnap = true } + + if (e.key === 'ArrowLeft') dx = -step + else if (e.key === 'ArrowRight') dx = step + else if (e.key === 'ArrowUp') dy = -step + else if (e.key === 'ArrowDown') dy = step else return e.preventDefault() updateObject(selected.id, (o) => { - const nx = snap8(o.x + dx) - const ny = snap8(o.y + dy) + const tx = o.x + dx + const ty = o.y + dy + const nx = useSnap ? snap8(tx) : tx + const ny = useSnap ? snap8(ty) : ty return { ...o, x: nx, y: ny } }) }, [selected, updateObject]) -- 2.52.0