import type { Doc } from '@blocksuite/store'; import { on, once } from '@blocksuite/blocks'; import type { OutlinePanelBody } from '../body/outline-panel-body.js'; import type { OutlineNoteCard } from '../card/outline-card.js'; /** * start drag notes * @param notes notes to drag */ export function startDragging(options: { onDragEnd?: (insertIndex?: number) => void; onDragMove?: (insertIdx?: number, indicatorTranslateY?: number) => void; outlineListContainer: HTMLElement; document: Document; host: Document | HTMLElement; container: OutlinePanelBody; doc: Doc; }) { const { document, host, container, onDragMove, onDragEnd, outlineListContainer, } = options; const maskElement = createMaskElement(document); const listContainerRect = outlineListContainer.getBoundingClientRect(); const children = Array.from( outlineListContainer.children ) as OutlineNoteCard[]; let idx: undefined | number; let indicatorTranslateY: undefined | number; container.renderRoot.append(maskElement); const insideListContainer = (e: MouseEvent) => { return ( e.clientX >= listContainerRect.left && e.clientX <= listContainerRect.right && e.clientY >= listContainerRect.top && e.clientY <= listContainerRect.bottom ); }; const disposeMove = on(container, 'mousemove', e => { if (!insideListContainer(e)) { idx = undefined; onDragMove?.(idx, 0); return; } idx = 0; for (const note of children) { if (note.invisible || !note.note) break; const topBoundary = listContainerRect.top + note.offsetTop - outlineListContainer.scrollTop; const midBoundary = topBoundary + note.offsetHeight / 2; const bottomBoundary = topBoundary + note.offsetHeight; if (e.clientY >= topBoundary && e.clientY <= bottomBoundary) { idx = e.clientY > midBoundary ? idx + 1 : idx; indicatorTranslateY = e.clientY > midBoundary ? bottomBoundary : topBoundary; indicatorTranslateY -= listContainerRect.top; onDragMove?.(idx, indicatorTranslateY); return; } ++idx; } onDragMove?.(idx); }); let ended = false; const dragEnd = () => { if (ended) return; ended = true; maskElement.remove(); disposeMove(); onDragEnd?.(idx); }; once(host as Document, 'mouseup', dragEnd); } function createMaskElement(doc: Document) { const mask = doc.createElement('div'); mask.style.height = '100vh'; mask.style.width = '100vw'; mask.style.position = 'fixed'; mask.style.left = '0'; mask.style.top = '0'; mask.style.zIndex = 'calc(var(--affine-z-index-popover, 0) + 3)'; mask.style.cursor = 'grabbing'; return mask; }