react-resizable 3.0.5 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "WebFetch(domain:github.com)",
5
+ "Bash(npx jest:*)",
6
+ "Bash(git tag:*)",
7
+ "Bash(gh release create:*)",
8
+ "Bash(gh issue close:*)",
9
+ "Bash(gh search:*)",
10
+ "WebFetch(domain:raw.githubusercontent.com)",
11
+ "Bash(curl:*)"
12
+ ]
13
+ },
14
+ "enableAllProjectMcpServers": true,
15
+ "enabledMcpjsonServers": [
16
+ "messenger"
17
+ ]
18
+ }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ### 3.1.1 (Dec 30, 2025)
4
+
5
+ - 🐛 Bugfix: Fix crash when `Resizable` child has a single child element (was not iterable). [#219](https://github.com/react-grid-layout/react-resizable/issues/219)
6
+ - 🐛 Bugfix: Fix `offsetParent` propType from `PropTypes.node` to `PropTypes.instanceOf(Element)`. [#220](https://github.com/react-grid-layout/react-resizable/pull/220)
7
+ - ✏ Chore: Update GitHub Actions workflows to latest versions.
8
+ - ✏ Chore: Add version display to demo page.
9
+
10
+ ### 3.1.0 (Dec 30, 2025)
11
+
12
+ - 🐛 Bugfix: Fix `onResizeStop` reporting stale size data due to React's batched state updates. The callback now uses the stored size from the last `onResize` call. [#250](https://github.com/react-grid-layout/react-resizable/pull/250)
13
+ - ➕ Feature: React 18 support.
14
+ - ✏ Chore: Migrate test suite from Enzyme to React Testing Library. [#249](https://github.com/react-grid-layout/react-resizable/pull/249)
15
+ - ✏ Chore: Update `react-draggable` to ^4.5.0.
16
+ - ✏ Chore: Update `react-test-renderer` to ^18.
17
+
3
18
  ### 3.0.5 (Mar 21, 2023)
4
19
 
5
20
  - 🐛 Bugfix: Make `width` and `height` conditionally required if an `axis` is set. See [#196](https://github.com/react-grid-layout/react-resizable/issues/196)
package/CLAUDE.md ADDED
@@ -0,0 +1,71 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ yarn
10
+
11
+ # Run tests with coverage
12
+ yarn test
13
+
14
+ # Run tests in watch mode
15
+ yarn unit
16
+
17
+ # Lint (ESLint + Flow)
18
+ yarn lint
19
+
20
+ # Type check only
21
+ yarn flow
22
+
23
+ # Build (transpile lib/ to build/)
24
+ yarn build
25
+
26
+ # Run dev server with examples
27
+ yarn dev
28
+
29
+ # Build examples for production
30
+ yarn build-example
31
+ ```
32
+
33
+ Run a single test file:
34
+ ```bash
35
+ npx jest __tests__/Resizable.test.js
36
+ ```
37
+
38
+ Run tests matching a pattern:
39
+ ```bash
40
+ npx jest --testNamePattern="snapshot"
41
+ ```
42
+
43
+ ## Architecture
44
+
45
+ This is a React component library providing resizable functionality via two main components:
46
+
47
+ ### Core Components (`lib/`)
48
+
49
+ - **Resizable.js** - Stateless base component. Wraps a child element with draggable resize handles using `react-draggable`'s `DraggableCore`. Computes size changes from drag deltas, applies constraints, and invokes callbacks. Does not manage state - parent must set `width`/`height` props from callback data.
50
+
51
+ - **ResizableBox.js** - Stateful wrapper around `<Resizable>`. Manages width/height state internally and renders a `<div>` with those dimensions. Simpler API for common use cases.
52
+
53
+ - **propTypes.js** - Shared Flow types and PropTypes definitions. Exports `resizableProps` object and types like `ResizeHandleAxis`, `ResizeCallbackData`, etc.
54
+
55
+ - **utils.js** - Helper `cloneElement()` that merges `style` and `className` when cloning React elements.
56
+
57
+ ### Key Implementation Details
58
+
59
+ - Resize handles are rendered as `<DraggableCore>` wrappers around handle elements
60
+ - Handle positions: `'s'`, `'w'`, `'e'`, `'n'`, `'sw'`, `'nw'`, `'se'`, `'ne'`
61
+ - The `runConstraints()` method applies min/max constraints and aspect ratio locking with slack tracking
62
+ - Position tracking via `lastHandleRect` compensates for element repositioning during north/west drags
63
+ - `transformScale` prop adjusts deltas when parent has CSS transform scaling
64
+
65
+ ### Build Output
66
+
67
+ `yarn build` transpiles `lib/*.js` to `build/` and copies source files as `*.js.flow` for Flow consumers.
68
+
69
+ ## Testing
70
+
71
+ Tests use Jest with Enzyme for shallow/mount rendering. Test files in `__tests__/` mirror the lib structure. Snapshot tests verify render output; unit tests verify resize behavior, constraint handling, and callback data.
package/README.md CHANGED
@@ -77,7 +77,7 @@ import { ResizableBox } from 'react-resizable';
77
77
  class Example extends React.Component {
78
78
  render() {
79
79
  return (
80
- <ResizableBox width={200} height={200} draggableOpts={{...}}
80
+ <ResizableBox width={200} height={200} draggableOpts={{grid: [25, 25]}}
81
81
  minConstraints={[100, 100]} maxConstraints={[300, 300]}>
82
82
  <span>Contents</span>
83
83
  </ResizableBox>
@@ -6,56 +6,48 @@ var React = _interopRequireWildcard(require("react"));
6
6
  var _reactDraggable = require("react-draggable");
7
7
  var _utils = require("./utils");
8
8
  var _propTypes = require("./propTypes");
9
- var _excluded = ["children", "className", "draggableOpts", "width", "height", "handle", "handleSize", "lockAspectRatio", "axis", "minConstraints", "maxConstraints", "onResize", "onResizeStop", "onResizeStart", "resizeHandles", "transformScale"];
10
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
11
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
12
- function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
13
- function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
14
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
15
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
16
- function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
17
- function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
18
- function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
19
- function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
20
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
9
+ const _excluded = ["children", "className", "draggableOpts", "width", "height", "handle", "handleSize", "lockAspectRatio", "axis", "minConstraints", "maxConstraints", "onResize", "onResizeStop", "onResizeStart", "resizeHandles", "transformScale"];
10
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
11
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
12
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
13
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
14
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
15
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
16
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
17
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
18
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
21
19
  // The base <Resizable> component.
22
20
  // This component does not have state and relies on the parent to set its props based on callback data.
23
- var Resizable = /*#__PURE__*/function (_React$Component) {
24
- _inheritsLoose(Resizable, _React$Component);
25
- function Resizable() {
26
- var _this;
27
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
28
- args[_key] = arguments[_key];
29
- }
30
- _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
31
- _this.handleRefs = {};
32
- _this.lastHandleRect = null;
33
- _this.slack = null;
34
- return _this;
21
+ class Resizable extends React.Component {
22
+ constructor() {
23
+ super(...arguments);
24
+ this.handleRefs = {};
25
+ this.lastHandleRect = null;
26
+ this.slack = null;
27
+ this.lastSize = null;
35
28
  }
36
- var _proto = Resizable.prototype;
37
- _proto.componentWillUnmount = function componentWillUnmount() {
29
+ componentWillUnmount() {
38
30
  this.resetData();
39
- };
40
- _proto.resetData = function resetData() {
41
- this.lastHandleRect = this.slack = null;
31
+ }
32
+ resetData() {
33
+ this.lastHandleRect = this.slack = this.lastSize = null;
42
34
  }
43
35
 
44
36
  // Clamp width and height within provided constraints
45
- ;
46
- _proto.runConstraints = function runConstraints(width, height) {
47
- var _this$props = this.props,
48
- minConstraints = _this$props.minConstraints,
49
- maxConstraints = _this$props.maxConstraints,
50
- lockAspectRatio = _this$props.lockAspectRatio;
37
+ runConstraints(width, height) {
38
+ const {
39
+ minConstraints,
40
+ maxConstraints,
41
+ lockAspectRatio
42
+ } = this.props;
51
43
  // short circuit
52
44
  if (!minConstraints && !maxConstraints && !lockAspectRatio) return [width, height];
53
45
 
54
46
  // If constraining to min and max, we need to also fit width and height to aspect ratio.
55
47
  if (lockAspectRatio) {
56
- var ratio = this.props.width / this.props.height;
57
- var deltaW = width - this.props.width;
58
- var deltaH = height - this.props.height;
48
+ const ratio = this.props.width / this.props.height;
49
+ const deltaW = width - this.props.width;
50
+ const deltaH = height - this.props.height;
59
51
 
60
52
  // Find which coordinate was greater and should push the other toward it.
61
53
  // E.g.:
@@ -67,15 +59,12 @@ var Resizable = /*#__PURE__*/function (_React$Component) {
67
59
  width = height * ratio;
68
60
  }
69
61
  }
70
- var oldW = width,
71
- oldH = height;
62
+ const [oldW, oldH] = [width, height];
72
63
 
73
64
  // Add slack to the values used to calculate bound position. This will ensure that if
74
65
  // we start removing slack, the element won't react to it right away until it's been
75
66
  // completely removed.
76
- var _ref = this.slack || [0, 0],
77
- slackW = _ref[0],
78
- slackH = _ref[1];
67
+ let [slackW, slackH] = this.slack || [0, 0];
79
68
  width += slackW;
80
69
  height += slackH;
81
70
  if (minConstraints) {
@@ -97,90 +86,108 @@ var Resizable = /*#__PURE__*/function (_React$Component) {
97
86
  *
98
87
  * @param {String} handlerName Handler name to wrap.
99
88
  * @return {Function} Handler function.
100
- */;
101
- _proto.resizeHandler = function resizeHandler(handlerName, axis) {
102
- var _this2 = this;
103
- return function (e, _ref2) {
104
- var node = _ref2.node,
105
- deltaX = _ref2.deltaX,
106
- deltaY = _ref2.deltaY;
89
+ */
90
+ resizeHandler(handlerName, axis) {
91
+ return (e, _ref) => {
92
+ let {
93
+ node,
94
+ deltaX,
95
+ deltaY
96
+ } = _ref;
107
97
  // Reset data in case it was left over somehow (should not be possible)
108
- if (handlerName === 'onResizeStart') _this2.resetData();
98
+ if (handlerName === 'onResizeStart') this.resetData();
109
99
 
110
100
  // Axis restrictions
111
- var canDragX = (_this2.props.axis === 'both' || _this2.props.axis === 'x') && axis !== 'n' && axis !== 's';
112
- var canDragY = (_this2.props.axis === 'both' || _this2.props.axis === 'y') && axis !== 'e' && axis !== 'w';
101
+ const canDragX = (this.props.axis === 'both' || this.props.axis === 'x') && axis !== 'n' && axis !== 's';
102
+ const canDragY = (this.props.axis === 'both' || this.props.axis === 'y') && axis !== 'e' && axis !== 'w';
113
103
  // No dragging possible.
114
104
  if (!canDragX && !canDragY) return;
115
105
 
116
106
  // Decompose axis for later use
117
- var axisV = axis[0];
118
- var axisH = axis[axis.length - 1]; // intentionally not axis[1], so that this catches axis === 'w' for example
107
+ const axisV = axis[0];
108
+ const axisH = axis[axis.length - 1]; // intentionally not axis[1], so that this catches axis === 'w' for example
119
109
 
120
110
  // Track the element being dragged to account for changes in position.
121
111
  // If a handle's position is changed between callbacks, we need to factor this in to the next callback.
122
112
  // Failure to do so will cause the element to "skip" when resized upwards or leftwards.
123
- var handleRect = node.getBoundingClientRect();
124
- if (_this2.lastHandleRect != null) {
113
+ const handleRect = node.getBoundingClientRect();
114
+ if (this.lastHandleRect != null) {
125
115
  // If the handle has repositioned on either axis since last render,
126
116
  // we need to increase our callback values by this much.
127
117
  // Only checking 'n', 'w' since resizing by 's', 'w' won't affect the overall position on page,
128
118
  if (axisH === 'w') {
129
- var deltaLeftSinceLast = handleRect.left - _this2.lastHandleRect.left;
119
+ const deltaLeftSinceLast = handleRect.left - this.lastHandleRect.left;
130
120
  deltaX += deltaLeftSinceLast;
131
121
  }
132
122
  if (axisV === 'n') {
133
- var deltaTopSinceLast = handleRect.top - _this2.lastHandleRect.top;
123
+ const deltaTopSinceLast = handleRect.top - this.lastHandleRect.top;
134
124
  deltaY += deltaTopSinceLast;
135
125
  }
136
126
  }
137
127
  // Storage of last rect so we know how much it has really moved.
138
- _this2.lastHandleRect = handleRect;
128
+ this.lastHandleRect = handleRect;
139
129
 
140
130
  // Reverse delta if using top or left drag handles.
141
131
  if (axisH === 'w') deltaX = -deltaX;
142
132
  if (axisV === 'n') deltaY = -deltaY;
143
133
 
144
134
  // Update w/h by the deltas. Also factor in transformScale.
145
- var width = _this2.props.width + (canDragX ? deltaX / _this2.props.transformScale : 0);
146
- var height = _this2.props.height + (canDragY ? deltaY / _this2.props.transformScale : 0);
135
+ let width = this.props.width + (canDragX ? deltaX / this.props.transformScale : 0);
136
+ let height = this.props.height + (canDragY ? deltaY / this.props.transformScale : 0);
147
137
 
148
138
  // Run user-provided constraints.
149
- var _this2$runConstraints = _this2.runConstraints(width, height);
150
- width = _this2$runConstraints[0];
151
- height = _this2$runConstraints[1];
152
- var dimensionsChanged = width !== _this2.props.width || height !== _this2.props.height;
139
+ [width, height] = this.runConstraints(width, height);
140
+
141
+ // For onResizeStop, use the last size from onResize rather than recalculating.
142
+ // This avoids issues where props.width/height are stale due to React's batched updates.
143
+ if (handlerName === 'onResizeStop' && this.lastSize) {
144
+ ({
145
+ width,
146
+ height
147
+ } = this.lastSize);
148
+ }
149
+ const dimensionsChanged = width !== this.props.width || height !== this.props.height;
150
+
151
+ // Store the size for use in onResizeStop. We do this after the onResizeStop check
152
+ // above so we don't overwrite the stored value with a potentially stale calculation.
153
+ if (handlerName !== 'onResizeStop') {
154
+ this.lastSize = {
155
+ width,
156
+ height
157
+ };
158
+ }
153
159
 
154
160
  // Call user-supplied callback if present.
155
- var cb = typeof _this2.props[handlerName] === 'function' ? _this2.props[handlerName] : null;
161
+ const cb = typeof this.props[handlerName] === 'function' ? this.props[handlerName] : null;
156
162
  // Don't call 'onResize' if dimensions haven't changed.
157
- var shouldSkipCb = handlerName === 'onResize' && !dimensionsChanged;
163
+ const shouldSkipCb = handlerName === 'onResize' && !dimensionsChanged;
158
164
  if (cb && !shouldSkipCb) {
159
- e.persist == null ? void 0 : e.persist();
165
+ e.persist?.();
160
166
  cb(e, {
161
- node: node,
167
+ node,
162
168
  size: {
163
- width: width,
164
- height: height
169
+ width,
170
+ height
165
171
  },
166
172
  handle: axis
167
173
  });
168
174
  }
169
175
 
170
176
  // Reset internal data
171
- if (handlerName === 'onResizeStop') _this2.resetData();
177
+ if (handlerName === 'onResizeStop') this.resetData();
172
178
  };
173
179
  }
174
180
 
175
181
  // Render a resize handle given an axis & DOM ref. Ref *must* be attached for
176
182
  // the underlying draggable library to work properly.
177
- ;
178
- _proto.renderResizeHandle = function renderResizeHandle(handleAxis, ref) {
179
- var handle = this.props.handle;
183
+ renderResizeHandle(handleAxis, ref) {
184
+ const {
185
+ handle
186
+ } = this.props;
180
187
  // No handle provided, make the default
181
188
  if (!handle) {
182
189
  return /*#__PURE__*/React.createElement("span", {
183
- className: "react-resizable-handle react-resizable-handle-" + handleAxis,
190
+ className: `react-resizable-handle react-resizable-handle-${handleAxis}`,
184
191
  ref: ref
185
192
  });
186
193
  }
@@ -190,59 +197,58 @@ var Resizable = /*#__PURE__*/function (_React$Component) {
190
197
  return handle(handleAxis, ref);
191
198
  }
192
199
  // Handle is a React component (composite or DOM).
193
- var isDOMElement = typeof handle.type === 'string';
194
- var props = _objectSpread({
195
- ref: ref
200
+ const isDOMElement = typeof handle.type === 'string';
201
+ const props = _objectSpread({
202
+ ref
196
203
  }, isDOMElement ? {} : {
197
- handleAxis: handleAxis
204
+ handleAxis
198
205
  });
199
206
  return /*#__PURE__*/React.cloneElement(handle, props);
200
- };
201
- _proto.render = function render() {
202
- var _this3 = this;
207
+ }
208
+ render() {
203
209
  // Pass along only props not meant for the `<Resizable>`.`
204
210
  // eslint-disable-next-line no-unused-vars
205
- var _this$props2 = this.props,
206
- children = _this$props2.children,
207
- className = _this$props2.className,
208
- draggableOpts = _this$props2.draggableOpts,
209
- width = _this$props2.width,
210
- height = _this$props2.height,
211
- handle = _this$props2.handle,
212
- handleSize = _this$props2.handleSize,
213
- lockAspectRatio = _this$props2.lockAspectRatio,
214
- axis = _this$props2.axis,
215
- minConstraints = _this$props2.minConstraints,
216
- maxConstraints = _this$props2.maxConstraints,
217
- onResize = _this$props2.onResize,
218
- onResizeStop = _this$props2.onResizeStop,
219
- onResizeStart = _this$props2.onResizeStart,
220
- resizeHandles = _this$props2.resizeHandles,
221
- transformScale = _this$props2.transformScale,
222
- p = _objectWithoutPropertiesLoose(_this$props2, _excluded);
211
+ const _this$props = this.props,
212
+ {
213
+ children,
214
+ className,
215
+ draggableOpts,
216
+ width,
217
+ height,
218
+ handle,
219
+ handleSize,
220
+ lockAspectRatio,
221
+ axis,
222
+ minConstraints,
223
+ maxConstraints,
224
+ onResize,
225
+ onResizeStop,
226
+ onResizeStart,
227
+ resizeHandles,
228
+ transformScale
229
+ } = _this$props,
230
+ p = _objectWithoutProperties(_this$props, _excluded);
223
231
 
224
232
  // What we're doing here is getting the child of this element, and cloning it with this element's props.
225
233
  // We are then defining its children as:
226
234
  // 1. Its original children (resizable's child's children), and
227
235
  // 2. One or more draggable handles.
228
236
  return (0, _utils.cloneElement)(children, _objectSpread(_objectSpread({}, p), {}, {
229
- className: (className ? className + " " : '') + "react-resizable",
230
- children: [].concat(children.props.children, resizeHandles.map(function (handleAxis) {
231
- var _this3$handleRefs$han;
237
+ className: `${className ? `${className} ` : ''}react-resizable`,
238
+ children: [...React.Children.toArray(children.props.children), ...resizeHandles.map(handleAxis => {
232
239
  // Create a ref to the handle so that `<DraggableCore>` doesn't have to use ReactDOM.findDOMNode().
233
- var ref = (_this3$handleRefs$han = _this3.handleRefs[handleAxis]) != null ? _this3$handleRefs$han : _this3.handleRefs[handleAxis] = /*#__PURE__*/React.createRef();
240
+ const ref = this.handleRefs[handleAxis] ?? (this.handleRefs[handleAxis] = /*#__PURE__*/React.createRef());
234
241
  return /*#__PURE__*/React.createElement(_reactDraggable.DraggableCore, _extends({}, draggableOpts, {
235
242
  nodeRef: ref,
236
- key: "resizableHandle-" + handleAxis,
237
- onStop: _this3.resizeHandler('onResizeStop', handleAxis),
238
- onStart: _this3.resizeHandler('onResizeStart', handleAxis),
239
- onDrag: _this3.resizeHandler('onResize', handleAxis)
240
- }), _this3.renderResizeHandle(handleAxis, ref));
241
- }))
243
+ key: `resizableHandle-${handleAxis}`,
244
+ onStop: this.resizeHandler('onResizeStop', handleAxis),
245
+ onStart: this.resizeHandler('onResizeStart', handleAxis),
246
+ onDrag: this.resizeHandler('onResize', handleAxis)
247
+ }), this.renderResizeHandle(handleAxis, ref));
248
+ })]
242
249
  }));
243
- };
244
- return Resizable;
245
- }(React.Component);
250
+ }
251
+ }
246
252
  exports.default = Resizable;
247
253
  Resizable.propTypes = _propTypes.resizableProps;
248
254
  Resizable.defaultProps = {
@@ -24,13 +24,14 @@ export default class Resizable extends React.Component<Props, void> {
24
24
  handleRefs: {[key: ResizeHandleAxis]: ReactRef<HTMLElement>} = {};
25
25
  lastHandleRect: ?ClientRect = null;
26
26
  slack: ?[number, number] = null;
27
+ lastSize: ?{width: number, height: number} = null;
27
28
 
28
29
  componentWillUnmount() {
29
30
  this.resetData();
30
31
  }
31
32
 
32
33
  resetData() {
33
- this.lastHandleRect = this.slack = null;
34
+ this.lastHandleRect = this.slack = this.lastSize = null;
34
35
  }
35
36
 
36
37
  // Clamp width and height within provided constraints
@@ -132,8 +133,20 @@ export default class Resizable extends React.Component<Props, void> {
132
133
  // Run user-provided constraints.
133
134
  [width, height] = this.runConstraints(width, height);
134
135
 
136
+ // For onResizeStop, use the last size from onResize rather than recalculating.
137
+ // This avoids issues where props.width/height are stale due to React's batched updates.
138
+ if (handlerName === 'onResizeStop' && this.lastSize) {
139
+ ({width, height} = this.lastSize);
140
+ }
141
+
135
142
  const dimensionsChanged = width !== this.props.width || height !== this.props.height;
136
143
 
144
+ // Store the size for use in onResizeStop. We do this after the onResizeStop check
145
+ // above so we don't overwrite the stored value with a potentially stale calculation.
146
+ if (handlerName !== 'onResizeStop') {
147
+ this.lastSize = {width, height};
148
+ }
149
+
137
150
  // Call user-supplied callback if present.
138
151
  const cb = typeof this.props[handlerName] === 'function' ? this.props[handlerName] : null;
139
152
  // Don't call 'onResize' if dimensions haven't changed.
@@ -188,7 +201,7 @@ export default class Resizable extends React.Component<Props, void> {
188
201
  ...p,
189
202
  className: `${className ? `${className} ` : ''}react-resizable`,
190
203
  children: [
191
- ...children.props.children,
204
+ ...React.Children.toArray(children.props.children),
192
205
  ...resizeHandles.map((handleAxis) => {
193
206
  // Create a ref to the handle so that `<DraggableCore>` doesn't have to use ReactDOM.findDOMNode().
194
207
  const ref = (this.handleRefs[handleAxis]) ?? (this.handleRefs[handleAxis] = React.createRef());