Skip to content

๐Ÿ”– feat & fix: Portal ์˜ค๋ฒ„๋ ˆ์ด ํŒจํ„ด ์ ์šฉ ๋ฐ Stack ์•„์ดํ…œ ๋“œ๋ž˜๊ทธ ์ ํ”„ ๋ฒ„๊ทธ ์ˆ˜์ •#21

Merged
y-minion merged 5 commits intodevelopfrom
feat/canvas-rendering
Feb 25, 2026

Conversation

@y-minion
Copy link
Copy Markdown
Contributor

๐Ÿ’ก ์ž‘์—… ์š”์•ฝ

  • Portal ํŒจํ„ด ๋„์ž…: Selection Overlay ๋“ฑ ์‹œ๊ฐ์  ๋ณด์กฐ ์š”์†Œ๋“ค์„ DOM ๋…ธ๋“œ ๊ณ„์ธต์œผ๋กœ๋ถ€ํ„ฐ ์™„์ „ํžˆ ๋ถ„๋ฆฌํ•˜์—ฌ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ ˆ์ด์•„์›ƒ ๊ฐ„์„ญ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๋ณ€๊ฒฝ(๋ฆฌํŒฉํ† ๋ง)ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Node Jump ๋ฒ„๊ทธ ํ•ด๊ฒฐ: ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(react-rnd) ๋‚ด๋ถ€์˜ ์ƒํƒœ ๊ด€๋ฆฌ ํ•œ๊ณ„๋กœ ๋ฐœ์ƒํ•˜๋˜ position: relative ์•„์ดํ…œ์˜ UI ํŠ€์–ด์–ด์˜ค๋ฆ„(๋ฒ„๊ทธ)์„ ์ตœ์ ํ™”๋œ ์‹œ์ ์— ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ› ๏ธ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ

1. โœจ Portal ํŒจํ„ด ์˜ค๋ฒ„๋ ˆ์ด ๋ฆฌํŒฉํ† ๋ง (Nago ์ž‘์—…)

Selection Overlay ๋“ฑ ํ•ธ๋“ค๋Ÿฌ UI๋ฅผ React Portal์„ ์ด์šฉํ•ด DOM ํŠธ๋ฆฌ ๋ฐ–์œผ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ๋ Œ๋”๋งํ•˜๋„๋ก ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.
์„ ํƒ ๊ฐ€์ด๋“œ๋ผ์ธ ์˜ค๋ฒ„๋ ˆ์ด ๋ฆฌํŒฉํ† ๋ง์— ๋”ฐ๋ผ, ๊ธฐ์กด์— ์Šคํƒ ๋…ธ๋“œ(Stack Component) ๋‚ด๋ถ€์— ์ž์ฒด์ ์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋˜ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ์‚ฌ์ด์ง• ํ•ธ๋“ค UI ์ฝ”๋“œ๋ฅผ ์‚ญ์ œํ–ˆ์Šต๋‹ˆ๋‹ค.
-> ์ด๋กœ์ธํ•ด item๋…ธ๋“œ๊ฐ€ stack๋…ธ๋“œ์˜ ๋ฐ–์œผ๋กœ ๋‚˜์™€ overflow:hidden ์ƒํ™ฉ์—์„œ๋„ ํ•ธ๋“ค๋Ÿฌui๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

2. ๐Ÿ› Stack ์•„์ดํ…œ ๋ฆฌ์‚ฌ์ด์ฆˆ ์งํ›„ ๋“œ๋ž˜๊ทธ ์ ํ”„ ๋ฒ„๊ทธ ํ•ด๊ฒฐ

[๋ฌธ์ œ์ ]

Stack ๋‚ด๋ถ€ ์•„์ดํ…œ(position: relative)์„ ๋งˆ์šฐ์Šค๋กœ ์š”์†Œ ์ƒ๋‹จ/์ขŒ์ธก ๋ฐฉํ–ฅ์œผ๋กœ ๋ฆฌ์‚ฌ์ด์ฆˆํ•  ๋•Œ !transform-none์œผ๋กœ DOM ๋ Œ๋”๋ง์—์„  ๋ง‰ํ˜€์žˆ์—ˆ์œผ๋‚˜, react-rnd ๋‚ด๋ถ€ ์ƒํƒœ์—” position ์ด๋™ ์ง€ํ‘œ๊ฐ€ ๋ˆ„์ ์œผ๋กœ ๊ณ„์‚ฐ๋˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์งํ›„, ์‚ฌ์šฉ์ž๊ฐ€ ๋“œ๋ž˜๊ทธ๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด ์–ต์ œ๋˜์–ด ์žˆ๋˜ ๋ˆ„์  transform ๊ฐ’์ด ํ•œ๊บผ๋ฒˆ์— ์ ์šฉ๋˜๋ฉด์„œ ํ™”๋ฉด ๋‚ด ๋‹ค๋ฅธ ์ง€์ ์œผ๋กœ ํฌ๊ฒŒ ์ ํ”„ํ•˜๋Š” ๋ฒ„๊ทธ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

[ํ•ด๊ฒฐ์ฑ…]

๋“œ๋ž˜๊ทธ ์‹œ์ž‘(onDragStart) ์‹œ์  ์ œ์ผ ์ƒ๋‹จ์— rndRef.current?.updatePosition({ x: 0, y: 0 })๋ฅผ ์„ ์–ธํ•˜์—ฌ react-rnd ๋‚ด๋ถ€์˜ DOM ์ƒํƒœ ์œ„์น˜๋ฅผ ํ•ญ์ƒ (0,0)์œผ๋กœ ๊ฐ•์ œ ๋ฆด๋ฆฌ์ฆˆ์‹œํ‚จ ๋‹ค์Œ ๋“œ๋ž˜๊ทธ ํ™œ์„ฑ(setIsTransformActive(true))์„ ์‹œ์ž‘ํ•˜๋„๋ก ๋ฐฉ์–ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

3. ๐Ÿ“ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ๋ฌธ์„œํ™”

์œ„์—์„œ ํ•ด๊ฒฐํ•œ react-rnd ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ Uncontrolled ํŠน์„ฑ(๋‚ด๋ถ€ ์ƒํƒœ ๋ˆ„์  ๊ณ„์‚ฐ)์—์„œ ๊ธฐ์ธํ•œ ๋ฒ„๊ทธ ๋ฐœ์ƒ ์›์ธ ๋ฐ ํ•ด๊ฒฐ ๊ณผ์ •์„ ์ƒ์„ธํ•˜๊ฒŒ ๊ธฐ์ˆ ํ•œ ๋ฌธ์„œ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ฒฝ๋กœ: .notes/troubleshooting/stack-item-resize-drag-jump.md

๐Ÿ” ํ™•์ธ (๋ฆฌ๋ทฐ) ์‚ฌํ•ญ

EditorNodeWrapper ๋‚ด๋ถ€ onDragStart์— ์ž‘์„ฑ๋œ react-rnd ๋‚ด๋ถ€ ์ƒํƒœ ๊ฐ•์ œ ๋ฆด๋ฆฌ์ฆˆ ๋กœ์ง์ด ๋‹ค๋ฅธ Node Type ์ด๋ฒคํŠธ์— ๋ฏธ์น˜๋Š” ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋Š” ์—†๋Š”์ง€ ํ™•์ธ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

Nago730 and others added 5 commits February 21, 2026 10:51
react-rnd accumulates internal position during resize.
!transform-none hides it visually, but when drag starts,
isTransformActive becomes true and the accumulated value
applies all at once causing the node to jump.

Fix: call rndRef.current?.updatePosition on onResizeStop
to reset react-rnd internal state for relative-positioned nodes.
Add troubleshooting doc for react-rnd internal position accumulation bug.
- Root cause: react-rnd accumulates internal position during resize,
  which is hidden by !transform-none but applied on drag start
- Fix: call rndRef.current?.updatePosition at the top of onDragStart,
  before setIsTransformActive(true) to reset internal lib state
[๋ฌธ์ œ ์ƒํ™ฉ]
- Stack ๋‚ด๋ถ€์˜ `position: relative` ์•„์ดํ…œ ๋ฆฌ์‚ฌ์ด์ฆˆ ํ›„ ๋“œ๋ž˜๊ทธ ์‹œ์ž‘ ์‹œ ๋…ธ๋“œ๊ฐ€ ์—‰๋šฑํ•œ ์œ„์น˜๋กœ ์ˆœ๊ฐ„์ด๋™(Jump)ํ•˜๋Š” ๋ฒ„๊ทธ ๋ฐœ์ƒ

[์›์ธ ๋ถ„์„]
- react-rnd๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์œ„์น˜ ๊ฐ’์„ ๊ณ„์† ๋ˆ„์ ํ•˜์—ฌ `transform: translate(x, y)`์œผ๋กœ ์‚ฌ์šฉํ•จ.
- Stack ์•„์ดํ…œ์˜ ๊ฒฝ์šฐ Flex ์ •๋ ฌ ์œ ์ง€๋ฅผ ์œ„ํ•ด ํ‰์†Œ `!transform-none` CSS ์†์„ฑ์œผ๋กœ ๋ฎ์–ด๋‘์ง€๋งŒ, ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ๋ฆฌ์‚ฌ์ด์ฆˆ(top/left ๋ฐฉํ–ฅ ํ•ธ๋“ค) ์‹œ position์ด ๊ณ„์† ๋ˆ„์ ๋จ.
- ๋“œ๋ž˜๊ทธ๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ(`onDragStart`) `setIsTransformActive(true)`๋ฅผ ํ†ตํ•ด `!transform-none`์ด ์ œ๊ฑฐ๋˜๋Š” ์ˆœ๊ฐ„, ๋ˆ„์ ๋˜์–ด ์žˆ๋˜ ๋‚ด๋ถ€ position ๊ฐ’์ด ํ•œ๊บผ๋ฒˆ์— ์ ์šฉ๋˜๋ฉฐ ํŠ€์–ด๋ฒ„๋ฆฌ๋Š” ํ˜„์ƒ.

[ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•]
- `onDragStart`์—์„œ `setIsTransformActive(true)`๋กœ transform ์†์„ฑ์„ ํ™œ์„ฑํ™”ํ•˜๊ธฐ ์ง์ „์— `rndRef.current?.updatePosition({ x: 0, y: 0 })`๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์ˆ˜์ •.
- React์˜ ์ƒํƒœ(`dragPosition`) ์—…๋ฐ์ดํŠธ๋งŒ์œผ๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‚ด๋ถ€ DOM ์กฐ์ž‘ ์ƒํƒœ๊ฐ€ ์™„์ „ํžˆ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ฉฐ, transform ํ™œ์„ฑํ™” ์ด์ „์— ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์šฐ์„  ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ํ•ญ์ƒ ๊นจ๋—ํ•œ ์ƒํƒœ๋กœ ๋“œ๋ž˜๊ทธ๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ.
- db์˜ ๋…ธ๋“œ ๋ฐ์ดํ„ฐ ์ˆ˜์ •
- portal์„ ํ†ตํ•ด ๋…ธ๋“œ์˜ ๋ฆฌ์‚ฌ์ด์ง• ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ Œ๋”๋งํ•จ์— ๋”ฐ๋ผ ์Šคํƒ ๋…ธ๋“œ๊ฐ€ ์ž์ฒด์ ์œผ๋กœ ๊ฐ™๊ณ  ์žˆ๋˜ ํ•ธ๋“ค ์‚ญ์ œ
@y-minion y-minion merged commit 8ccdc16 into develop Feb 25, 2026
1 check passed
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