슬래시 메뉴 스크롤 계산 분리

This commit is contained in:
2026-07-27 10:41:17 +09:00
parent ab1b2a32c1
commit 3cc99ebeec
7 changed files with 89 additions and 13 deletions

View File

@@ -57,6 +57,7 @@ import {
DEFAULT_SLASH_MENU_HEIGHT,
DEFAULT_SLASH_MENU_WIDTH
} from '../../lib/markdown-slash-menu-position.js'
import { calculateSlashMenuScrollTop } from '../../lib/markdown-slash-menu-scroll.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'
@@ -2497,16 +2498,12 @@ const scrollLiveSlashHighlightedIntoView = () => {
return
}
const itemTop = highlightedItem.offsetTop
const itemBottom = itemTop + highlightedItem.offsetHeight
const viewTop = menu.scrollTop
const viewBottom = viewTop + menu.clientHeight
if (itemTop < viewTop) {
menu.scrollTop = itemTop
} else if (itemBottom > viewBottom) {
menu.scrollTop = itemBottom - menu.clientHeight
}
menu.scrollTop = calculateSlashMenuScrollTop({
itemTop: highlightedItem.offsetTop,
itemHeight: highlightedItem.offsetHeight,
viewTop: menu.scrollTop,
viewHeight: menu.clientHeight
})
})
}

View File

@@ -62,6 +62,7 @@
| lib/markdown-toc.js | 공개 게시글 TOC용 H1~H3 제목 추출과 앵커 ID 생성 |
| lib/markdown-slash-commands.js | 관리자 Markdown-first 에디터 슬래시 명령 목록과 삽입 줄 정의, 미디어 명령 action 판별, 미디어 명령 지연 commit 무시·슬래시 원문 줄 교체 삽입 helper |
| lib/markdown-slash-menu-position.js | 관리자 Markdown-first 에디터 슬래시 메뉴 뷰포트 위치 보정 helper |
| lib/markdown-slash-menu-scroll.js | 관리자 Markdown-first 에디터 슬래시 메뉴 선택 항목 표시용 scrollTop 계산 helper |
| lib/markdown-inline.js | 공개·관리자 공통 인라인 마크다운 파서, 링크·굵게·기울임·인라인 코드·첨자·인라인 색상 토큰(`::color[텍스트]`) 변환, 링크·굵게·기울임·색상 내부 중첩 인라인 문법과 `<br>` 줄바꿈 처리, 라이브 멀티라인 본문의 기본 불릿/번호 목록 HTML 변환과 contenteditable 목록 마커 기준 커서 offset 계산·직렬화 |
| lib/post-tag-limit.js | 게시물별 태그 최대 개수 기본값·허용 범위·정규화 |
| lib/analytics-shared.js | 통계 추적 경로 필터·체류/스크롤 상수(클라이언트·서버 공용) |
@@ -123,6 +124,7 @@
| tests/markdown-editor-history.test.js | 관리자 Markdown 에디터 undo/redo 히스토리 항목과 선택 범위 보정 단위 회귀 테스트 |
| tests/markdown-editor-media.test.js | 관리자 Markdown 에디터 미디어 선택 helper의 종류·선택 가능 여부·미리보기·선택 상태·블록 생성 단위 회귀 테스트 |
| tests/markdown-slash-commands.test.js | 관리자 슬래시 명령 파싱·미디어 action·포커스 대상·원문 줄 교체 삽입 단위 회귀 테스트 |
| tests/markdown-slash-menu-scroll.test.js | 관리자 슬래시 메뉴 선택 항목 scrollTop 보정 단위 테스트 |
| tests/markdown-block-parser.test.js | 공개 Markdown 본문 블록 파싱 단위 회귀 테스트 |
| tests/markdown-fenced-meta.test.js | Markdown fenced 블록 시작·종료 줄 탐색, 본문 수집, 메타 파싱 단위 회귀 테스트 |
| tests/markdown-quote.test.js | Markdown 인용 옵션 파싱과 편집 줄 변환 단위 회귀 테스트 |

View File

@@ -1,5 +1,10 @@
# 업데이트 이력
## v1.11.85
- 관리자 Markdown 에디터의 슬래시 메뉴 선택 항목 스크롤 계산을 `markdown-slash-menu-scroll` helper로 분리.
- 슬래시 메뉴 선택 항목의 위·아래 스크롤 보정 단위 테스트 추가.
## v1.11.84
- 관리자 Markdown 에디터의 슬래시 메뉴 재배치 이벤트 리스너를 안정적인 참조로 정리.

View File

@@ -0,0 +1,32 @@
/**
* 슬래시 메뉴 선택 항목이 보이도록 필요한 scrollTop을 계산한다.
* @param {Object} options - 계산 옵션
* @param {number} options.itemTop - 항목의 메뉴 내부 위쪽 위치
* @param {number} options.itemHeight - 항목 높이
* @param {number} options.viewTop - 현재 메뉴 scrollTop
* @param {number} options.viewHeight - 메뉴 표시 높이
* @returns {number} 적용할 scrollTop
*/
export const calculateSlashMenuScrollTop = ({
itemTop,
itemHeight,
viewTop,
viewHeight
}) => {
const safeItemTop = Number.isFinite(itemTop) ? itemTop : 0
const safeItemHeight = Number.isFinite(itemHeight) ? Math.max(0, itemHeight) : 0
const safeViewTop = Number.isFinite(viewTop) ? Math.max(0, viewTop) : 0
const safeViewHeight = Number.isFinite(viewHeight) ? Math.max(0, viewHeight) : 0
const itemBottom = safeItemTop + safeItemHeight
const viewBottom = safeViewTop + safeViewHeight
if (safeItemTop < safeViewTop) {
return Math.max(0, safeItemTop)
}
if (itemBottom > viewBottom) {
return Math.max(0, itemBottom - safeViewHeight)
}
return safeViewTop
}

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "sori.studio",
"version": "1.11.84",
"version": "1.11.85",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sori.studio",
"version": "1.11.84",
"version": "1.11.85",
"hasInstallScript": true,
"dependencies": {
"@nuxtjs/tailwindcss": "^6.14.0",

View File

@@ -1,6 +1,6 @@
{
"name": "sori.studio",
"version": "1.11.84",
"version": "1.11.85",
"private": true,
"type": "module",
"imports": {

View File

@@ -0,0 +1,40 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { calculateSlashMenuScrollTop } from '../lib/markdown-slash-menu-scroll.js'
test('슬래시 메뉴 항목이 보이는 범위 안이면 현재 scrollTop을 유지한다', () => {
assert.equal(calculateSlashMenuScrollTop({
itemTop: 48,
itemHeight: 32,
viewTop: 40,
viewHeight: 120
}), 40)
})
test('슬래시 메뉴 항목이 위로 벗어나면 항목 위쪽으로 스크롤한다', () => {
assert.equal(calculateSlashMenuScrollTop({
itemTop: 20,
itemHeight: 32,
viewTop: 60,
viewHeight: 120
}), 20)
})
test('슬래시 메뉴 항목이 아래로 벗어나면 항목 아래쪽이 보이도록 스크롤한다', () => {
assert.equal(calculateSlashMenuScrollTop({
itemTop: 180,
itemHeight: 32,
viewTop: 60,
viewHeight: 120
}), 92)
})
test('슬래시 메뉴 스크롤 계산은 잘못된 숫자를 안전한 기본값으로 보정한다', () => {
assert.equal(calculateSlashMenuScrollTop({
itemTop: Number.NaN,
itemHeight: -10,
viewTop: -20,
viewHeight: Number.POSITIVE_INFINITY
}), 0)
})