diff --git a/app/src/assets/scss/protyle/_toolbar.scss b/app/src/assets/scss/protyle/_toolbar.scss index 97229f835..bac744ab4 100644 --- a/app/src/assets/scss/protyle/_toolbar.scss +++ b/app/src/assets/scss/protyle/_toolbar.scss @@ -7,10 +7,6 @@ border-radius: var(--b3-border-radius); display: flex; - &__transition { - transition: top .15s cubic-bezier(0, 0, .2, 1) 0ms; - } - &__item { color: var(--b3-theme-on-surface); border: 0; diff --git a/app/src/protyle/toolbar/index.ts b/app/src/protyle/toolbar/index.ts index db499d8ed..592833c5b 100644 --- a/app/src/protyle/toolbar/index.ts +++ b/app/src/protyle/toolbar/index.ts @@ -164,17 +164,15 @@ export class Toolbar { this.element.classList.add("fn__none"); return; } - this.element.classList.remove("fn__none", "protyle-toolbar__transition"); - + const rangePosition = getSelectionPosition(nodeElement, range, true); + this.element.classList.remove("fn__none"); this.toolbarHeight = this.element.clientHeight; - const rangePosition = getSelectionPosition(nodeElement, range, this.element.clientWidth); - const y = rangePosition.isToolbarAtBottom ? + const y = rangePosition.isBottom ? Math.min(rangePosition.top + 4, protyle.element.getBoundingClientRect().bottom - this.toolbarHeight) : Math.max(rangePosition.top - this.toolbarHeight - 4, protyle.element.getBoundingClientRect().top + 30); this.element.setAttribute("data-inity", y + Constants.ZWSP + protyle.contentElement.scrollTop.toString()); - setPosition(this.element, rangePosition.left, y); + setPosition(this.element, rangePosition.left - this.element.clientWidth / 4, y); - this.element.classList.add("protyle-toolbar__transition"); this.element.querySelectorAll(".protyle-toolbar__item--current").forEach(item => { item.classList.remove("protyle-toolbar__item--current"); }); diff --git a/app/src/protyle/util/selection.ts b/app/src/protyle/util/selection.ts index 79d6a8e0f..4864eb13a 100644 --- a/app/src/protyle/util/selection.ts +++ b/app/src/protyle/util/selection.ts @@ -194,7 +194,7 @@ export const getEditorRange = (element: Element): Range => { return range; }; -export const getSelectionPosition = (nodeElement: Element, range?: Range, toolbarWidth?: number) => { +export const getSelectionPosition = (nodeElement: Element, range?: Range, useDirect = false) => { if (!range) { range = getEditorRange(nodeElement); } @@ -261,25 +261,26 @@ export const getSelectionPosition = (nodeElement: Element, range?: Range, toolba } else { const rects = range.getClientRects(); // 由于长度过长折行,光标在行首时有多个 rects https://github.com/siyuan-note/siyuan/issues/6156 if (range.toString()) { - const selection = window.getSelection(); - // 判断选择方向 - const isBackward = selection && "direction" in selection ? - (selection as { direction: "forward" | "backward" | "none" }).direction === "backward" - : range.startContainer === selection?.focusNode && range.startOffset === selection?.focusOffset; - let isToolbarAtBottom = false; - if (!isBackward) { - // 检查是否有多个垂直位置不同的矩形 - isToolbarAtBottom = rects.length > 1 && Array.from(rects).some((rect: DOMRect) => rect.top !== rects[0].top); + if (useDirect) { + const selection = window.getSelection(); + // 判断选择方向 + const isBackward = (selection && "direction" in selection && selection.direction !== "none") ? + selection.direction === "backward" + : range.startContainer === selection?.focusNode && range.startOffset === selection?.focusOffset; + const isBottom = !isBackward && rects[0].top !== rects[rects.length - 1].top; + return { + // 向左选择:使用第一个矩形的左边界;向右选择:使用最后一个矩形的右边界 + left: isBackward ? rects[0].left : rects[rects.length - 1].right, + // 如果向右选择时有多个垂直位置不同的矩形:使用最后一个矩形的下边界;否则使用第一个矩形的上边界 + top: isBottom ? rects[rects.length - 1].bottom : rects[0].top, + isBottom + }; + } else { + return { // 选中多行不应遮挡第一行 https://github.com/siyuan-note/siyuan/issues/7541 + left: rects[rects.length - 1].left, + top: rects[0].top + }; } - - return { - // 向左选择:使用第一个矩形的左边界;向右选择:使用最后一个矩形的右边界 - // 减去工具栏宽度的1/4:将工具栏中不太常用的按钮往右偏一点 - left: (isBackward ? rects[0].left : rects[rects.length - 1].right) - (toolbarWidth || 0) / 4, - // 如果向右选择时有多个垂直位置不同的矩形:使用最后一个矩形的下边界;否则使用第一个矩形的上边界 - top: isToolbarAtBottom ? rects[rects.length - 1].bottom : rects[0].top, - isToolbarAtBottom: isToolbarAtBottom, - }; } else { return { // 代码块首 https://github.com/siyuan-note/siyuan/issues/13113 left: rects[rects.length - 1].left,