From f4c561708f3f611701e48a5e758930fc6967e685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Wed, 29 Apr 2026 15:49:24 -0300 Subject: [PATCH 1/2] Grid: lock document cursor during resize gesture Set `documentElement.style.cursor` while `useDraggable.isDragging` is true so the resize cue persists even when the pointer leaves the handle's hit area. Resolve the document via `ownerDocument` so the lock works inside the block-editor iframe. --- packages/grid/src/resize-handle.tsx | 31 ++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/grid/src/resize-handle.tsx b/packages/grid/src/resize-handle.tsx index 49f8d0060acf09..508fa703452d58 100644 --- a/packages/grid/src/resize-handle.tsx +++ b/packages/grid/src/resize-handle.tsx @@ -8,7 +8,8 @@ import clsx from 'clsx'; /** * WordPress dependencies */ -import { useThrottle } from '@wordpress/compose'; +import { useEffect, useRef } from '@wordpress/element'; +import { useMergeRefs, useThrottle } from '@wordpress/compose'; /** * Internal dependencies @@ -57,14 +58,38 @@ function ResizeHandle( { itemId, verticalResizable = true, }: ResizeHandleProps ) { - const { attributes, listeners, setNodeRef } = useDraggable( { + const { attributes, listeners, setNodeRef, isDragging } = useDraggable( { id: 'draggable', data: { itemId }, } ); + // Track the rendered node so we can resolve `ownerDocument` for the + // cursor lock — needed when the grid lives inside an iframe (e.g. + // the block-editor canvas). + const nodeRef = useRef< HTMLElement | null >( null ); + const mergedRef = useMergeRefs( [ nodeRef, setNodeRef ] ); + + // Lock the document cursor while the gesture is active. Without + // this, the OS pointer reverts to the default arrow as soon as it + // leaves the handle's hit area, even though the resize is still + // in progress. + useEffect( () => { + if ( ! isDragging ) { + return; + } + const cursor = verticalResizable ? 'nwse-resize' : 'ew-resize'; + const root = ( nodeRef.current?.ownerDocument ?? document ) + .documentElement; + const previous = root.style.cursor; + root.style.cursor = cursor; + return () => { + root.style.cursor = previous; + }; + }, [ isDragging, verticalResizable ] ); + return (
Date: Wed, 29 Apr 2026 16:02:29 -0300 Subject: [PATCH 2/2] Grid: clear tile cursor while a gesture is active MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The inline `cursor: grab` on each tile beat the document-level resize cursor lock — keeping the hand pointer visible mid-resize. Drop the inline cursor while `interacting` so the gesture's document cursor propagates without an inline override on a descendant. --- packages/grid/src/grid-item.tsx | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/grid/src/grid-item.tsx b/packages/grid/src/grid-item.tsx index 735b472a705e2a..53707aa8596d3c 100644 --- a/packages/grid/src/grid-item.tsx +++ b/packages/grid/src/grid-item.tsx @@ -17,6 +17,21 @@ import ResizeHandle from './resize-handle'; import type { DashboardGridLayoutItem } from './types'; import styles from './grid-item.module.css'; +function getItemCursor( + disabled: boolean, + interacting: boolean +): React.CSSProperties[ 'cursor' ] { + if ( disabled ) { + return 'default'; + } + + if ( interacting ) { + return undefined; + } + + return 'grab'; +} + type GridItemProps = { /** * The layout item containing grid positioning information. @@ -132,7 +147,12 @@ export function GridItem( { ) }`, gridRowEnd: `span ${ item.height || 1 }`, - cursor: disabled ? 'default' : 'grab', + + // Suppress the grab hint while any gesture is active so the + // inline `cursor` on the tile doesn't override the gesture's + // document-level cursor (e.g. the resize lock). Setting + // `undefined` leaves the property off the DOM. + cursor: getItemCursor( disabled, interacting ), }; const itemClassName = clsx(