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.
- package/.claude/settings.local.json +18 -0
- package/CHANGELOG.md +15 -0
- package/CLAUDE.md +71 -0
- package/README.md +1 -1
- package/build/Resizable.js +121 -115
- package/build/Resizable.js.flow +15 -2
- package/build/ResizableBox.js +56 -59
- package/build/propTypes.js +14 -15
- package/build/propTypes.js.flow +2 -1
- package/build/utils.js +7 -7
- package/dist/bundle.js +488 -6
- package/package.json +28 -28
- package/.eslintrc +0 -38
|
@@ -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>
|
package/build/Resizable.js
CHANGED
|
@@ -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
|
-
|
|
10
|
-
function
|
|
11
|
-
function
|
|
12
|
-
function
|
|
13
|
-
function _objectWithoutPropertiesLoose(
|
|
14
|
-
function ownKeys(
|
|
15
|
-
function _objectSpread(
|
|
16
|
-
function _defineProperty(
|
|
17
|
-
function _toPropertyKey(
|
|
18
|
-
function _toPrimitive(
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
37
|
-
_proto.componentWillUnmount = function componentWillUnmount() {
|
|
29
|
+
componentWillUnmount() {
|
|
38
30
|
this.resetData();
|
|
39
|
-
}
|
|
40
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
deltaX
|
|
106
|
-
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')
|
|
98
|
+
if (handlerName === 'onResizeStart') this.resetData();
|
|
109
99
|
|
|
110
100
|
// Axis restrictions
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
118
|
-
|
|
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
|
-
|
|
124
|
-
if (
|
|
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
|
-
|
|
119
|
+
const deltaLeftSinceLast = handleRect.left - this.lastHandleRect.left;
|
|
130
120
|
deltaX += deltaLeftSinceLast;
|
|
131
121
|
}
|
|
132
122
|
if (axisV === 'n') {
|
|
133
|
-
|
|
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
|
-
|
|
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
|
-
|
|
146
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
161
|
+
const cb = typeof this.props[handlerName] === 'function' ? this.props[handlerName] : null;
|
|
156
162
|
// Don't call 'onResize' if dimensions haven't changed.
|
|
157
|
-
|
|
163
|
+
const shouldSkipCb = handlerName === 'onResize' && !dimensionsChanged;
|
|
158
164
|
if (cb && !shouldSkipCb) {
|
|
159
|
-
e.persist
|
|
165
|
+
e.persist?.();
|
|
160
166
|
cb(e, {
|
|
161
|
-
node
|
|
167
|
+
node,
|
|
162
168
|
size: {
|
|
163
|
-
width
|
|
164
|
-
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')
|
|
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
|
-
|
|
179
|
-
|
|
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:
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
ref
|
|
200
|
+
const isDOMElement = typeof handle.type === 'string';
|
|
201
|
+
const props = _objectSpread({
|
|
202
|
+
ref
|
|
196
203
|
}, isDOMElement ? {} : {
|
|
197
|
-
handleAxis
|
|
204
|
+
handleAxis
|
|
198
205
|
});
|
|
199
206
|
return /*#__PURE__*/React.cloneElement(handle, props);
|
|
200
|
-
}
|
|
201
|
-
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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:
|
|
230
|
-
children: [
|
|
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
|
-
|
|
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:
|
|
237
|
-
onStop:
|
|
238
|
-
onStart:
|
|
239
|
-
onDrag:
|
|
240
|
-
}),
|
|
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
|
-
|
|
245
|
-
}(React.Component);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
246
252
|
exports.default = Resizable;
|
|
247
253
|
Resizable.propTypes = _propTypes.resizableProps;
|
|
248
254
|
Resizable.defaultProps = {
|
package/build/Resizable.js.flow
CHANGED
|
@@ -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());
|