diff --git a/frontend/app/block/block.tsx b/frontend/app/block/block.tsx index 126f208813..b09cc1bdcc 100644 --- a/frontend/app/block/block.tsx +++ b/frontend/app/block/block.tsx @@ -144,6 +144,7 @@ const BlockFull = memo(({ nodeModel, viewModel }: FullBlockProps) => { const focusElemRef = useRef(null); const blockRef = useRef(null); const contentRef = useRef(null); + const pendingFocusRafRef = useRef(null); const [blockClicked, setBlockClicked] = useState(false); const blockView = useAtomValue(waveEnv.getBlockMetaKeyAtom(nodeModel.blockId, "view")) ?? ""; const isFocused = useAtomValue(nodeModel.isFocused); @@ -156,6 +157,14 @@ const BlockFull = memo(({ nodeModel, viewModel }: FullBlockProps) => { const innerRect = useDebouncedNodeInnerRect(nodeModel); const noPadding = useAtomValueSafe(viewModel.noPadding); + useEffect(() => { + return () => { + if (pendingFocusRafRef.current != null) { + cancelAnimationFrame(pendingFocusRafRef.current); + } + }; + }, []); + useLayoutEffect(() => { setBlockClicked(isFocused); }, [isFocused]); @@ -221,11 +230,21 @@ const BlockFull = memo(({ nodeModel, viewModel }: FullBlockProps) => { ); const setFocusTarget = useCallback(() => { + if (pendingFocusRafRef.current != null) { + cancelAnimationFrame(pendingFocusRafRef.current); + pendingFocusRafRef.current = null; + } const ok = viewModel?.giveFocus?.(); if (ok) { return; } focusElemRef.current?.focus({ preventScroll: true }); + pendingFocusRafRef.current = requestAnimationFrame(() => { + pendingFocusRafRef.current = null; + if (blockRef.current?.contains(document.activeElement)) { + viewModel?.giveFocus?.(); + } + }); }, [viewModel]); const focusFromPointerEnter = useCallback(