158 lines
5.4 KiB
JavaScript
158 lines
5.4 KiB
JavaScript
import { computed, ref } from 'vue'
|
|
import {
|
|
addSlashSuppressedLine,
|
|
clampSlashHighlightedIndex,
|
|
filterSlashCommands,
|
|
removeSlashSuppressedLine
|
|
} from '../lib/markdown-slash-commands.js'
|
|
|
|
/**
|
|
* 관리자 Markdown 에디터의 슬래시 메뉴 상태를 관리한다.
|
|
* @returns {{
|
|
* liveSlashSourceLine: import('vue').Ref<number|null>,
|
|
* liveSlashQuery: import('vue').Ref<string>,
|
|
* liveSlashHighlightedIndex: import('vue').Ref<number>,
|
|
* liveSlashMenuPosition: import('vue').Ref<{ top: number, left: number }>,
|
|
* liveSlashMenuRef: import('vue').Ref<HTMLElement|null>,
|
|
* liveSlashInsertLine: import('vue').Ref<number|null>,
|
|
* liveSlashSuppressedLines: import('vue').Ref<Set<number>>,
|
|
* liveSlashKeyboardNav: import('vue').Ref<boolean>,
|
|
* liveSlashVisible: import('vue').ComputedRef<boolean>,
|
|
* liveSlashSuppressedLineList: import('vue').ComputedRef<number[]>,
|
|
* visibleLiveSlashCommands: import('vue').ComputedRef<import('../lib/markdown-slash-commands.js').MarkdownSlashCommand[]>,
|
|
* clearLiveSlashState: () => void,
|
|
* openLiveSlashMenu: (sourceLine: number, query: string) => void,
|
|
* isLiveSlashLineSuppressed: (line: number) => boolean,
|
|
* suppressLiveSlashLine: (line: number) => void,
|
|
* releaseLiveSlashLine: (line: number) => void,
|
|
* resetLiveSlashHighlightedIndex: () => void,
|
|
* clampLiveSlashHighlightedIndex: (commandCount: number) => void,
|
|
* startLiveSlashKeyboardNavigation: (durationMs?: number) => void,
|
|
* stopLiveSlashKeyboardNavigation: () => void
|
|
* }} 슬래시 메뉴 상태와 액션
|
|
*/
|
|
export const useAdminMarkdownSlashMenu = () => {
|
|
const liveSlashSourceLine = ref(null)
|
|
const liveSlashQuery = ref('')
|
|
const liveSlashHighlightedIndex = ref(0)
|
|
const liveSlashMenuPosition = ref({ top: 0, left: 0 })
|
|
const liveSlashMenuRef = ref(null)
|
|
const liveSlashInsertLine = ref(null)
|
|
const liveSlashSuppressedLines = ref(new Set())
|
|
const liveSlashKeyboardNav = ref(false)
|
|
let liveSlashKeyboardNavTimer = null
|
|
|
|
const liveSlashVisible = computed(() => liveSlashSourceLine.value !== null)
|
|
const liveSlashSuppressedLineList = computed(() => [...liveSlashSuppressedLines.value])
|
|
const visibleLiveSlashCommands = computed(() => filterSlashCommands(liveSlashQuery.value))
|
|
|
|
/**
|
|
* 슬래시 메뉴 입력 상태를 초기화한다.
|
|
* @returns {void}
|
|
*/
|
|
const clearLiveSlashState = () => {
|
|
liveSlashSourceLine.value = null
|
|
liveSlashQuery.value = ''
|
|
liveSlashHighlightedIndex.value = 0
|
|
}
|
|
|
|
/**
|
|
* 슬래시 메뉴를 지정 줄과 검색어로 연다.
|
|
* @param {number} sourceLine - 슬래시 명령이 입력된 줄
|
|
* @param {string} query - 검색어
|
|
* @returns {void}
|
|
*/
|
|
const openLiveSlashMenu = (sourceLine, query) => {
|
|
liveSlashSourceLine.value = sourceLine
|
|
liveSlashQuery.value = String(query ?? '')
|
|
}
|
|
|
|
/**
|
|
* 슬래시 메뉴가 억제된 줄인지 확인한다.
|
|
* @param {number} line - 줄 번호
|
|
* @returns {boolean} 억제 여부
|
|
*/
|
|
const isLiveSlashLineSuppressed = (line) => liveSlashSuppressedLines.value.has(line)
|
|
|
|
/**
|
|
* 지정 줄에서 슬래시 메뉴가 다시 열리지 않도록 억제한다.
|
|
* @param {number} line - 줄 번호
|
|
* @returns {void}
|
|
*/
|
|
const suppressLiveSlashLine = (line) => {
|
|
liveSlashSuppressedLines.value = addSlashSuppressedLine(liveSlashSuppressedLines.value, line)
|
|
}
|
|
|
|
/**
|
|
* 지정 줄의 슬래시 메뉴 억제를 해제한다.
|
|
* @param {number} line - 줄 번호
|
|
* @returns {void}
|
|
*/
|
|
const releaseLiveSlashLine = (line) => {
|
|
liveSlashSuppressedLines.value = removeSlashSuppressedLine(liveSlashSuppressedLines.value, line)
|
|
}
|
|
|
|
/**
|
|
* 슬래시 메뉴 하이라이트를 첫 항목으로 되돌린다.
|
|
* @returns {void}
|
|
*/
|
|
const resetLiveSlashHighlightedIndex = () => {
|
|
liveSlashHighlightedIndex.value = 0
|
|
}
|
|
|
|
/**
|
|
* 슬래시 메뉴 하이라이트를 명령 개수 안으로 보정한다.
|
|
* @param {number} commandCount - 표시 가능한 명령 개수
|
|
* @returns {void}
|
|
*/
|
|
const clampLiveSlashHighlightedIndex = (commandCount) => {
|
|
liveSlashHighlightedIndex.value = clampSlashHighlightedIndex(liveSlashHighlightedIndex.value, commandCount)
|
|
}
|
|
|
|
/**
|
|
* 키보드 탐색 중 mouseenter 하이라이트를 잠시 무시한다.
|
|
* @param {number} [durationMs=200] - 유지 시간(ms)
|
|
* @returns {void}
|
|
*/
|
|
const startLiveSlashKeyboardNavigation = (durationMs = 200) => {
|
|
liveSlashKeyboardNav.value = true
|
|
globalThis.clearTimeout(liveSlashKeyboardNavTimer)
|
|
liveSlashKeyboardNavTimer = globalThis.setTimeout(() => {
|
|
liveSlashKeyboardNav.value = false
|
|
}, durationMs)
|
|
}
|
|
|
|
/**
|
|
* 슬래시 메뉴 키보드 탐색 타이머를 정리한다.
|
|
* @returns {void}
|
|
*/
|
|
const stopLiveSlashKeyboardNavigation = () => {
|
|
globalThis.clearTimeout(liveSlashKeyboardNavTimer)
|
|
liveSlashKeyboardNavTimer = null
|
|
liveSlashKeyboardNav.value = false
|
|
}
|
|
|
|
return {
|
|
liveSlashSourceLine,
|
|
liveSlashQuery,
|
|
liveSlashHighlightedIndex,
|
|
liveSlashMenuPosition,
|
|
liveSlashMenuRef,
|
|
liveSlashInsertLine,
|
|
liveSlashSuppressedLines,
|
|
liveSlashKeyboardNav,
|
|
liveSlashVisible,
|
|
liveSlashSuppressedLineList,
|
|
visibleLiveSlashCommands,
|
|
clearLiveSlashState,
|
|
openLiveSlashMenu,
|
|
isLiveSlashLineSuppressed,
|
|
suppressLiveSlashLine,
|
|
releaseLiveSlashLine,
|
|
resetLiveSlashHighlightedIndex,
|
|
clampLiveSlashHighlightedIndex,
|
|
startLiveSlashKeyboardNavigation,
|
|
stopLiveSlashKeyboardNavigation
|
|
}
|
|
}
|