From 785e6ca02fb17498ae3dc6fedfcd87ddf1f490b3 Mon Sep 17 00:00:00 2001 From: Andrey Mazepas Date: Tue, 29 Oct 2024 19:22:56 -0300 Subject: [PATCH] Applying patch from https://github.com/react-grid-layout/react-resizable/issues/237 --- lib/Resizable.js | 53 +++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/lib/Resizable.js b/lib/Resizable.js index a2eede3d..45bbe7b2 100644 --- a/lib/Resizable.js +++ b/lib/Resizable.js @@ -24,6 +24,9 @@ export default class Resizable extends React.Component { handleRefs: {[key: ResizeHandleAxis]: ReactRef} = {}; lastHandleRect: ?ClientRect = null; slack: ?[number, number] = null; + // We add these two fields to remember the state at start of resizing + dragStart = null; + sizeStart = null; componentWillUnmount() { this.resetData(); @@ -87,9 +90,15 @@ export default class Resizable extends React.Component { * @return {Function} Handler function. */ resizeHandler(handlerName: 'onResize' | 'onResizeStart' | 'onResizeStop', axis: ResizeHandleAxis): Function { - return (e: SyntheticEvent<>, {node, deltaX, deltaY}: DragCallbackData) => { + // Using `lastX` and `lastY` rather than `deltaX` and `deltaY` (see longer comment below) + return (e: SyntheticEvent<>, {node, lastX, lastY}: DragCallbackData) => { // Reset data in case it was left over somehow (should not be possible) - if (handlerName === 'onResizeStart') this.resetData(); + if (handlerName === 'onResizeStart') { + this.resetData(); + // Remembering state at start of resizing + this.dragStart = { x: lastX, y: lastY }; + this.sizeStart = { x: this.props.width, y: this.props.height }; + } // Axis restrictions const canDragX = (this.props.axis === 'both' || this.props.axis === 'x') && axis !== 'n' && axis !== 's'; @@ -97,38 +106,14 @@ export default class Resizable extends React.Component { // No dragging possible. if (!canDragX && !canDragY) return; - // Decompose axis for later use - const axisV = axis[0]; - const axisH = axis[axis.length - 1]; // intentionally not axis[1], so that this catches axis === 'w' for example - - // Track the element being dragged to account for changes in position. - // If a handle's position is changed between callbacks, we need to factor this in to the next callback. - // Failure to do so will cause the element to "skip" when resized upwards or leftwards. - const handleRect = node.getBoundingClientRect(); - if (this.lastHandleRect != null) { - // If the handle has repositioned on either axis since last render, - // we need to increase our callback values by this much. - // Only checking 'n', 'w' since resizing by 's', 'w' won't affect the overall position on page, - if (axisH === 'w') { - const deltaLeftSinceLast = handleRect.left - this.lastHandleRect.left; - deltaX += deltaLeftSinceLast; - } - if (axisV === 'n') { - const deltaTopSinceLast = handleRect.top - this.lastHandleRect.top; - deltaY += deltaTopSinceLast; - } - } - // Storage of last rect so we know how much it has really moved. - this.lastHandleRect = handleRect; - - // Reverse delta if using top or left drag handles. - if (axisH === 'w') deltaX = -deltaX; - if (axisV === 'n') deltaY = -deltaY; - - // Update w/h by the deltas. Also factor in transformScale. - let width = this.props.width + (canDragX ? deltaX / this.props.transformScale : 0); - let height = this.props.height + (canDragY ? deltaY / this.props.transformScale : 0); - + // In order to fix an issue where resizing does not correctly follow the mouse cursor, we use the `lastX` and + // `lastY` properties of the mouse event rather than the `deltaX` and `deltaY` properties. + // + // This approach is more robust because `lastX` and `lastY` are absolute values and will remain true even if some + // events get dropped, whereas calculating the resulting width with `deltaX` and `deltaY` in a cumulative way will + // accumulate errors if some events are skipped. + let width = this.sizeStart.x + (canDragX ? lastX - (this.dragStart.x ?? 0) : 0); + let height = this.sizeStart.y + (canDragY ? lastY - (this.dragStart.y ?? 0) : 0); // Run user-provided constraints. [width, height] = this.runConstraints(width, height);