From ca334247e2df119d317fcb77e38f1e6225b2f628 Mon Sep 17 00:00:00 2001 From: Kevin Brey Date: Tue, 12 May 2026 14:49:13 -0500 Subject: [PATCH 1/2] fix(example): convert example to typescript --- .../{ExampleLayout.js => ExampleLayout.tsx} | 24 ++++++++++++++----- examples/{example.js => example.tsx} | 0 webpack.config.js | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) rename examples/{ExampleLayout.js => ExampleLayout.tsx} (93%) rename examples/{example.js => example.tsx} (100%) diff --git a/examples/ExampleLayout.js b/examples/ExampleLayout.tsx similarity index 93% rename from examples/ExampleLayout.js rename to examples/ExampleLayout.tsx index 3aab998c..3b82338f 100644 --- a/examples/ExampleLayout.js +++ b/examples/ExampleLayout.tsx @@ -1,9 +1,12 @@ import React from 'react'; import Resizable from '../lib/Resizable'; import ResizableBox from '../lib/ResizableBox'; +import type {ResizeCallbackData} from '../lib/propTypes'; import 'style-loader!css-loader!../css/styles.css'; -/* global __VERSION__, __GIT_TAG__, __GIT_COMMIT__ */ +declare const __VERSION__: string; +declare const __GIT_TAG__: string; +declare const __GIT_COMMIT__: string; // Update the version badge in the header function updateVersionBadge() { @@ -23,7 +26,7 @@ if (typeof document !== 'undefined') { } } -const CustomResizeHandle = React.forwardRef((props, ref) => { +const CustomResizeHandle = React.forwardRef & {handleAxis?: string}>((props, ref) => { const {handleAxis, ...restProps} = props; return (
{ ); }); -export default class ExampleLayout extends React.Component<{}, {width: number, height: number}> { - state = { +type State = { + width: number; + height: number; + absoluteWidth: number; + absoluteHeight: number; + absoluteLeft: number; + absoluteTop: number; +}; + +export default class ExampleLayout extends React.Component<{}, State> { + state: State = { width: 200, height: 200, absoluteWidth: 200, @@ -49,12 +61,12 @@ export default class ExampleLayout extends React.Component<{}, {width: number, h }; // On top layout - onFirstBoxResize = (event, {element, size, handle}) => { + onFirstBoxResize = (_event: React.SyntheticEvent, {size}: ResizeCallbackData) => { this.setState({width: size.width, height: size.height}); }; // On bottom layout. Used to resize the center element around its flex parent. - onResizeAbsolute = (event, {element, size, handle}) => { + onResizeAbsolute = (_event: React.SyntheticEvent, {size, handle}: ResizeCallbackData) => { this.setState((state) => { let newLeft = state.absoluteLeft; let newTop = state.absoluteTop; diff --git a/examples/example.js b/examples/example.tsx similarity index 100% rename from examples/example.js rename to examples/example.tsx diff --git a/webpack.config.js b/webpack.config.js index 4ab106f2..9299ad5c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -28,7 +28,7 @@ module.exports = { bail: isProduction, context: __dirname, entry: { - test: "./examples/example.js", + test: "./examples/example.tsx", }, output: { path: path.join(__dirname, "examples"), From b3f3915ffd4240553ee061a4c149d2329c0efab5 Mon Sep 17 00:00:00 2001 From: Kevin Brey Date: Tue, 12 May 2026 14:56:18 -0500 Subject: [PATCH 2/2] fix: fit locked aspect ratio with least squares --- __tests__/Resizable.test.tsx | 5 +++-- lib/Resizable.tsx | 18 ++++++------------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/__tests__/Resizable.test.tsx b/__tests__/Resizable.test.tsx index 4fa81ae6..1df7b195 100644 --- a/__tests__/Resizable.test.tsx +++ b/__tests__/Resizable.test.tsx @@ -390,12 +390,13 @@ describe('render Resizable', () => { expect(props.onResize).not.toHaveBeenCalled(); const seHandler = resizableRef.current.resizeHandler('onResize', 'se'); seHandler(mockEvent, { node, deltaX: w, deltaY: h }); + const expected = 50 + (w + h) / 2; expect(props.onResize).toHaveBeenLastCalledWith( mockEvent, expect.objectContaining({ size: { - height: 50 + Math.max(w, h), - width: 50 + Math.max(w, h), + height: expected, + width: expected, }, }) ); diff --git a/lib/Resizable.tsx b/lib/Resizable.tsx index 65507c83..e3dee340 100644 --- a/lib/Resizable.tsx +++ b/lib/Resizable.tsx @@ -41,18 +41,12 @@ export default class Resizable extends React.Component { // If constraining to min and max, we need to also fit width and height to aspect ratio. if (lockAspectRatio) { const ratio = this.props.width / this.props.height; - const deltaW = width - this.props.width; - const deltaH = height - this.props.height; - - // Find which coordinate was greater and should push the other toward it. - // E.g.: - // ratio = 1, deltaW = 10, deltaH = 5, deltaH should become 10. - // ratio = 2, deltaW = 10, deltaH = 6, deltaW should become 12. - if (Math.abs(deltaW) > Math.abs(deltaH * ratio)) { - height = width / ratio; - } else { - width = height * ratio; - } + + // Project (width, height) onto the line w = ratio * h. + // Distributes tracking error across both axes instead of forcing one to overshoot. + // t = (w * ratio + h) / (ratio^2 + 1), new_w = t * ratio, new_h = t + height = (width * ratio + height) / (ratio * ratio + 1); + width = height * ratio; } const [oldW, oldH] = [width, height];