슬래시 메뉴 위치 계산 분리
This commit is contained in:
@@ -52,6 +52,11 @@ import {
|
||||
resolveSlashCommand,
|
||||
shouldIgnorePendingMediaSlashCommit
|
||||
} from '../../lib/markdown-slash-commands.js'
|
||||
import {
|
||||
calculateSlashMenuPosition,
|
||||
DEFAULT_SLASH_MENU_HEIGHT,
|
||||
DEFAULT_SLASH_MENU_WIDTH
|
||||
} from '../../lib/markdown-slash-menu-position.js'
|
||||
import { buildCalloutOpenerLine, CALLOUT_BACKGROUND_OPTIONS, QUOTE_BACKGROUND_OPTIONS } from '../../lib/markdown-callout.js'
|
||||
import { buildCodeFenceOpener } from '../../lib/markdown-code-block.js'
|
||||
import { buildToggleOpenerLine } from '../../lib/markdown-toggle.js'
|
||||
@@ -145,8 +150,6 @@ const liveSlashMenuPosition = ref({ top: 0, left: 0 })
|
||||
/** @type {import('vue').Ref<HTMLElement|null>} 슬래시 메뉴 DOM */
|
||||
const liveSlashMenuRef = ref(null)
|
||||
|
||||
/** 슬래시 메뉴 예상 높이(px) — 렌더 전 위치 계산용 */
|
||||
const LIVE_SLASH_MENU_ESTIMATED_HEIGHT = 280
|
||||
/** @type {import('vue').Ref<number|null>} 슬래시 후 미디어 삽입 줄 */
|
||||
const liveSlashInsertLine = ref(null)
|
||||
/** @type {import('vue').Ref<Set<number>>} ESC로 슬래시 메뉴만 닫은 줄(0-based) */
|
||||
@@ -2324,44 +2327,6 @@ const handlePreviewKeydownCapture = (event) => {
|
||||
* @param {{ lineIndex: number, mergedLine: string }} payload - 병합 위치·결과 줄
|
||||
* @returns {void}
|
||||
*/
|
||||
/**
|
||||
* 슬래시 메뉴 좌표를 뷰포트 안으로 맞춘다.
|
||||
* @param {number} top - 후보 top(px)
|
||||
* @param {number} left - 후보 left(px)
|
||||
* @param {number} menuHeight - 메뉴 높이
|
||||
* @param {number} menuWidth - 메뉴 너비
|
||||
* @param {number} anchorTop - 기준 요소 top(위로 넘칠 때)
|
||||
* @returns {{ top: number, left: number }}
|
||||
*/
|
||||
const clampSlashMenuPosition = (top, left, menuHeight, menuWidth, anchorTop) => {
|
||||
const gap = 4
|
||||
const padding = 8
|
||||
const viewportBottom = window.innerHeight - padding
|
||||
const viewportRight = window.innerWidth - padding
|
||||
let nextTop = top
|
||||
|
||||
if (nextTop + menuHeight > viewportBottom) {
|
||||
const aboveTop = anchorTop - menuHeight - gap
|
||||
|
||||
if (aboveTop >= padding) {
|
||||
nextTop = aboveTop
|
||||
} else {
|
||||
nextTop = Math.max(padding, viewportBottom - menuHeight)
|
||||
}
|
||||
}
|
||||
|
||||
let nextLeft = left
|
||||
|
||||
if (nextLeft + menuWidth > viewportRight) {
|
||||
nextLeft = viewportRight - menuWidth
|
||||
}
|
||||
|
||||
return {
|
||||
top: nextTop,
|
||||
left: Math.max(padding, nextLeft)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 슬래시 메뉴 컴포넌트가 노출한 실제 DOM 엘리먼트를 반환한다.
|
||||
* @returns {HTMLElement|null} 메뉴 엘리먼트
|
||||
@@ -2393,17 +2358,19 @@ const updatePreviewSlashMenuPosition = () => {
|
||||
|
||||
const rect = element.getBoundingClientRect()
|
||||
const menuEl = getLiveSlashMenuElement()
|
||||
const menuHeight = menuEl?.offsetHeight || LIVE_SLASH_MENU_ESTIMATED_HEIGHT
|
||||
const menuWidth = menuEl?.offsetWidth || 288
|
||||
const menuHeight = menuEl?.offsetHeight || DEFAULT_SLASH_MENU_HEIGHT
|
||||
const menuWidth = menuEl?.offsetWidth || DEFAULT_SLASH_MENU_WIDTH
|
||||
const gap = 4
|
||||
|
||||
liveSlashMenuPosition.value = clampSlashMenuPosition(
|
||||
rect.bottom + gap,
|
||||
rect.left,
|
||||
liveSlashMenuPosition.value = calculateSlashMenuPosition({
|
||||
top: rect.bottom + gap,
|
||||
left: rect.left,
|
||||
menuHeight,
|
||||
menuWidth,
|
||||
rect.top
|
||||
)
|
||||
anchorTop: rect.top,
|
||||
viewportHeight: window.innerHeight,
|
||||
viewportWidth: window.innerWidth
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2423,18 +2390,20 @@ const updateWriteSlashMenuPosition = () => {
|
||||
const coords = getTextareaCaretCoordinates(textarea, lineStart)
|
||||
const rect = textarea.getBoundingClientRect()
|
||||
const menuEl = getLiveSlashMenuElement()
|
||||
const menuHeight = menuEl?.offsetHeight || LIVE_SLASH_MENU_ESTIMATED_HEIGHT
|
||||
const menuWidth = menuEl?.offsetWidth || 288
|
||||
const menuHeight = menuEl?.offsetHeight || DEFAULT_SLASH_MENU_HEIGHT
|
||||
const menuWidth = menuEl?.offsetWidth || DEFAULT_SLASH_MENU_WIDTH
|
||||
const gap = 4
|
||||
const anchorTop = rect.top + coords.top - textarea.scrollTop
|
||||
|
||||
liveSlashMenuPosition.value = clampSlashMenuPosition(
|
||||
anchorTop + coords.height + gap,
|
||||
rect.left + coords.left - textarea.scrollLeft,
|
||||
liveSlashMenuPosition.value = calculateSlashMenuPosition({
|
||||
top: anchorTop + coords.height + gap,
|
||||
left: rect.left + coords.left - textarea.scrollLeft,
|
||||
menuHeight,
|
||||
menuWidth,
|
||||
anchorTop
|
||||
)
|
||||
anchorTop,
|
||||
viewportHeight: window.innerHeight,
|
||||
viewportWidth: window.innerWidth
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user