diff --git a/app/src/block/popover.ts b/app/src/block/popover.ts index c1db412f9..e85927da8 100644 --- a/app/src/block/popover.ts +++ b/app/src/block/popover.ts @@ -22,7 +22,7 @@ export const initBlockPopover = (app: App) => { if (aElement) { let tip = aElement.getAttribute("aria-label") || aElement.getAttribute("data-inline-memo-content"); if (aElement.classList.contains("av__celltext")) { - if (aElement.offsetWidth > aElement.parentElement.clientWidth - 11) { + if (aElement.offsetWidth > aElement.parentElement.clientWidth - 5) { // 只能减左边 padding,换行时字体会穿透到右侧 padding if (aElement.querySelector(".av__cellicon")) { tip = `${aElement.firstChild.textContent} → ${aElement.lastChild.textContent}`; } else { diff --git a/app/src/menus/index.ts b/app/src/menus/index.ts index 0069b4dbe..dd7191094 100644 --- a/app/src/menus/index.ts +++ b/app/src/menus/index.ts @@ -22,7 +22,8 @@ export class Menus { return; } let target = event.target as HTMLElement; - while (target && !target.parentElement.isEqualNode(document.querySelector("body"))) { + while (target && target.parentElement // ⌃⇥ 后点击会为空 + && !target.parentElement.isEqualNode(document.querySelector("body"))) { event.preventDefault(); const dataType = target.getAttribute("data-type"); if (dataType === "tab-header") { diff --git a/app/src/protyle/render/av/render.ts b/app/src/protyle/render/av/render.ts index 763470b93..18cc671c0 100644 --- a/app/src/protyle/render/av/render.ts +++ b/app/src/protyle/render/av/render.ts @@ -7,6 +7,7 @@ import {unicode2Emoji} from "../../../emoji"; import {focusBlock} from "../../util/selection"; import {isMac} from "../../util/compatibility"; import {hasClosestByClassName} from "../../util/hasClosest"; +import {stickyRow} from "./row"; export const avRender = (element: Element, protyle: IProtyle, cb?: () => void) => { let avElements: Element[] = []; @@ -240,12 +241,19 @@ ${cell.color ? `color:${cell.color};` : ""}">${text}`; if (left) { e.querySelector(".av__scroll").scrollLeft = left; } + + const editRect = protyle.contentElement.getBoundingClientRect(); if (headerTransform) { (e.querySelector(".av__row--header") as HTMLElement).style.transform = headerTransform; + } else { + stickyRow(e, editRect, "top"); } if (footerTransform) { (e.querySelector(".av__row--footer") as HTMLElement).style.transform = footerTransform; + } else { + stickyRow(e, editRect, "bottom"); } + if (selectCellId) { const newCellElement = e.querySelector(`.av__row[data-id="${selectCellId.split(Constants.ZWSP)[0]}"] .av__cell[data-col-id="${selectCellId.split(Constants.ZWSP)[1]}"]`); if (newCellElement) { diff --git a/app/src/protyle/render/av/row.ts b/app/src/protyle/render/av/row.ts index 0355e0d16..d03b44a80 100644 --- a/app/src/protyle/render/av/row.ts +++ b/app/src/protyle/render/av/row.ts @@ -89,3 +89,30 @@ export const insertAttrViewBlockAnimation = (blockElement: Element, size: number }); previousElement.insertAdjacentHTML("afterend", html); }; + +export const stickyRow = (blockElement: HTMLElement, elementRect: DOMRect, status: "top" | "bottom" | "all") => { + const scrollRect = blockElement.querySelector(".av__scroll").getBoundingClientRect(); + const headerElement = blockElement.querySelector(".av__row--header") as HTMLElement; + if (headerElement && (status === "top" || status === "all")) { + const distance = Math.floor(elementRect.top - scrollRect.top); + if (distance > 0 && distance < scrollRect.height) { + headerElement.style.transform = `translateY(${distance}px)`; + } else { + headerElement.style.transform = ""; + } + } + + const footerElement = blockElement.querySelector(".av__row--footer") as HTMLElement; + if (footerElement && (status === "bottom" || status === "all")) { + if (footerElement.querySelector(".av__calc--ashow")) { + const distance = Math.ceil(elementRect.bottom - footerElement.parentElement.getBoundingClientRect().bottom); + if (distance < 0 && -distance < scrollRect.height) { + footerElement.style.transform = `translateY(${distance}px)`; + } else { + footerElement.style.transform = ""; + } + } else { + footerElement.style.transform = ""; + } + } +} diff --git a/app/src/protyle/scroll/event.ts b/app/src/protyle/scroll/event.ts index f37f099ae..61e56e4ab 100644 --- a/app/src/protyle/scroll/event.ts +++ b/app/src/protyle/scroll/event.ts @@ -4,6 +4,7 @@ import {fetchPost} from "../../util/fetch"; import {onGet} from "../util/onGet"; import {isMobile} from "../../util/functions"; import {hasClosestBlock, hasClosestByClassName} from "../util/hasClosest"; +import {stickyRow} from "../render/av/row"; let getIndexTimeout: number; export const scrollEvent = (protyle: IProtyle, element: HTMLElement) => { @@ -24,29 +25,7 @@ export const scrollEvent = (protyle: IProtyle, element: HTMLElement) => { if (item.dataset.render !== "true") { return; } - const scrollRect = item.querySelector(".av__scroll").getBoundingClientRect(); - const headerElement = item.querySelector(".av__row--header") as HTMLElement; - if (headerElement) { - const distance = Math.floor(elementRect.top - scrollRect.top); - if (distance > 0 && distance < scrollRect.height) { - headerElement.style.transform = `translateY(${distance}px)`; - } else { - headerElement.style.transform = ""; - } - } - const footerElement = item.querySelector(".av__row--footer") as HTMLElement; - if (footerElement) { - if (footerElement.querySelector(".av__calc--ashow")) { - const distance = Math.ceil(elementRect.bottom - footerElement.parentElement.getBoundingClientRect().bottom); - if (distance < 0 && -distance < scrollRect.height) { - footerElement.style.transform = `translateY(${distance}px)`; - } else { - footerElement.style.transform = ""; - } - } else { - footerElement.style.transform = ""; - } - } + stickyRow(item, elementRect, "all"); }); if (!protyle.element.classList.contains("block__edit") && !isMobile()) { diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index eda424ccb..9f16c52d9 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -76,7 +76,7 @@ import {removeSearchMark} from "../toolbar/util"; import {activeBlur, hideKeyboardToolbar} from "../../mobile/util/keyboardToolbar"; import {commonClick} from "./commonClick"; import {avClick, avContextmenu, updateAVName} from "../render/av/action"; -import {updateHeader} from "../render/av/row"; +import {stickyRow, updateHeader} from "../render/av/row"; export class WYSIWYG { public lastHTMLs: { [key: string]: string } = {}; @@ -382,14 +382,14 @@ export class WYSIWYG { const oldWidth = dragElement.clientWidth; const dragColId = dragElement.getAttribute("data-col-id"); let newWidth: string; + const scrollElement = nodeElement.querySelector(".av__scroll"); + const contentRect = protyle.contentElement.getBoundingClientRect() documentSelf.onmousemove = (moveEvent: MouseEvent) => { newWidth = Math.max(oldWidth + (moveEvent.clientX - event.clientX), 58) + "px"; - const scrollElement = hasClosestByClassName(dragElement, "av__scroll"); - if (scrollElement) { - scrollElement.querySelectorAll(".av__row, .av__row--footer").forEach(item => { - (item.querySelector(`[data-col-id="${dragColId}"]`) as HTMLElement).style.width = newWidth; - }); - } + scrollElement.querySelectorAll(".av__row, .av__row--footer").forEach(item => { + (item.querySelector(`[data-col-id="${dragColId}"]`) as HTMLElement).style.width = newWidth; + }); + stickyRow(nodeElement, contentRect, "bottom"); }; documentSelf.onmouseup = () => {