블록 에디터 줄바꿈과 핸들 표시 보정
This commit is contained in:
@@ -439,9 +439,9 @@ const setBlockRef = (element, index) => {
|
||||
if (
|
||||
!isComposingText.value
|
||||
&& isTextBlock(editorBlocks.value[index])
|
||||
&& element.innerText !== editorBlocks.value[index]?.text
|
||||
&& element.textContent !== editorBlocks.value[index]?.text
|
||||
) {
|
||||
element.innerText = editorBlocks.value[index]?.text || ''
|
||||
element.textContent = editorBlocks.value[index]?.text || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -516,7 +516,49 @@ const updateSlashMenuDirection = (index) => {
|
||||
const getTextBlockDomText = (index) => {
|
||||
const element = blockRefs.value[index]
|
||||
|
||||
return element?.innerText.replace(/\n$/, '') || ''
|
||||
return element?.textContent || ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재 선택 영역에 문단 내부 줄바꿈을 삽입
|
||||
* @param {number} index - 블록 인덱스
|
||||
* @returns {void}
|
||||
*/
|
||||
const insertSoftLineBreak = (index) => {
|
||||
const block = editorBlocks.value[index]
|
||||
const element = blockRefs.value[index]
|
||||
|
||||
if (!block || !element) {
|
||||
return
|
||||
}
|
||||
|
||||
element.focus()
|
||||
const selection = window.getSelection()
|
||||
|
||||
if (!selection) {
|
||||
return
|
||||
}
|
||||
|
||||
const range = selection?.rangeCount ? selection.getRangeAt(0) : document.createRange()
|
||||
|
||||
if (!selection.rangeCount || !element.contains(range.commonAncestorContainer)) {
|
||||
range.selectNodeContents(element)
|
||||
range.collapse(false)
|
||||
}
|
||||
|
||||
range.deleteContents()
|
||||
const lineBreak = document.createTextNode('\n')
|
||||
range.insertNode(lineBreak)
|
||||
range.setStartAfter(lineBreak)
|
||||
range.collapse(true)
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
|
||||
block.text = getTextBlockDomText(index)
|
||||
activeBlockId.value = block.id
|
||||
slashQuery.value = ''
|
||||
updateSlashMenuDirection(index)
|
||||
emitContent()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -685,7 +727,7 @@ const applyMarkdownShortcut = (block, index) => {
|
||||
const element = blockRefs.value[index]
|
||||
|
||||
if (element) {
|
||||
element.innerText = block.text
|
||||
element.textContent = block.text
|
||||
focusBlock(index)
|
||||
}
|
||||
})
|
||||
@@ -750,7 +792,7 @@ const applyCommand = (command) => {
|
||||
const element = blockRefs.value[index]
|
||||
|
||||
if (element) {
|
||||
element.innerText = ''
|
||||
element.textContent = ''
|
||||
}
|
||||
|
||||
slashQuery.value = ''
|
||||
@@ -1018,7 +1060,13 @@ const handleEnter = (event, index) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.shiftKey && isTextBlock(currentBlock)) {
|
||||
if (currentBlock.type === 'code') {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.shiftKey && isTextBlock(currentBlock) && currentBlock.type !== 'code') {
|
||||
event.preventDefault()
|
||||
insertSoftLineBreak(index)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1033,10 +1081,6 @@ const handleEnter = (event, index) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (currentBlock.type === 'code' && !event.shiftKey) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
|
||||
if (['divider', 'image', 'gallery', 'toggle', 'embed'].includes(currentBlock.type)) {
|
||||
@@ -1254,9 +1298,9 @@ defineExpose({
|
||||
<div
|
||||
v-for="(block, index) in editorBlocks"
|
||||
:key="block.id"
|
||||
class="admin-block-editor__row group/block relative rounded transition-colors"
|
||||
class="admin-block-editor__row group/block relative isolate rounded"
|
||||
:class="{
|
||||
'admin-block-editor__row--selected bg-[#eff1f2] ring-1 ring-[#d8dde1]': selectedBlockId === block.id,
|
||||
'admin-block-editor__row--selected': selectedBlockId === block.id,
|
||||
'admin-block-editor__row--dragging opacity-50': draggingBlockId === block.id,
|
||||
'admin-block-editor__row--text': isTextBlock(block),
|
||||
'admin-block-editor__row--structure': !isTextBlock(block)
|
||||
@@ -1266,7 +1310,7 @@ defineExpose({
|
||||
@drop="dropBlock($event, index)"
|
||||
>
|
||||
<button
|
||||
class="admin-block-editor__handle absolute -left-10 top-1 z-10 grid size-7 cursor-grab place-items-center rounded text-sm font-semibold text-[#8e9cac] opacity-0 transition-colors hover:bg-[#eff1f2] hover:text-[#394047] group-hover/block:opacity-100 focus:opacity-100 active:cursor-grabbing"
|
||||
class="admin-block-editor__handle absolute -left-9 bottom-0 top-0 z-10 flex w-5 cursor-grab items-stretch justify-center rounded opacity-0 outline-none transition-opacity duration-150 group-hover/block:opacity-100 focus:opacity-100 active:cursor-grabbing"
|
||||
type="button"
|
||||
draggable="true"
|
||||
aria-label="블록 이동 및 선택"
|
||||
@@ -1276,7 +1320,9 @@ defineExpose({
|
||||
@dragstart="startBlockDrag($event, block)"
|
||||
@dragend="finishBlockDrag"
|
||||
>
|
||||
<span aria-hidden="true">⋮⋮</span>
|
||||
<span class="admin-block-editor__handle-container" aria-hidden="true">
|
||||
<span class="admin-block-editor__handle-grabber"></span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<hr v-if="block.type === 'divider'" class="admin-block-editor__divider border-line">
|
||||
@@ -1513,6 +1559,62 @@ defineExpose({
|
||||
color: #1f2328;
|
||||
}
|
||||
|
||||
.admin-block-editor__row::before {
|
||||
position: absolute;
|
||||
inset: -4px -10px;
|
||||
z-index: -1;
|
||||
border-radius: 8px;
|
||||
background: transparent;
|
||||
content: "";
|
||||
opacity: 0;
|
||||
transform: scaleX(0.995);
|
||||
transition:
|
||||
background-color 160ms ease,
|
||||
opacity 160ms ease,
|
||||
transform 160ms ease;
|
||||
}
|
||||
|
||||
.admin-block-editor__row:hover::before,
|
||||
.admin-block-editor__row--selected::before {
|
||||
background: #eff1f2;
|
||||
opacity: 1;
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
.admin-block-editor__handle {
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.admin-block-editor__handle-container {
|
||||
display: flex;
|
||||
width: 16px;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.admin-block-editor__handle-grabber {
|
||||
display: block;
|
||||
width: 4px;
|
||||
height: 20px;
|
||||
border-radius: 999px;
|
||||
background: #8d969f;
|
||||
opacity: 0.72;
|
||||
transition:
|
||||
height 160ms ease,
|
||||
background-color 160ms ease,
|
||||
opacity 160ms ease;
|
||||
}
|
||||
|
||||
.admin-block-editor__row:hover .admin-block-editor__handle-grabber,
|
||||
.admin-block-editor__row--selected .admin-block-editor__handle-grabber,
|
||||
.admin-block-editor__handle:focus .admin-block-editor__handle-grabber {
|
||||
height: 100%;
|
||||
background: #5d6670;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.admin-block-editor__row + .admin-block-editor__row--text {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user