Skip to content

Commit 729d96d

Browse files
authored
fix(props): revert removal of props passthrough from #133 (#144)
This breaks certain important use cases such as wrapping a Resizable in a Draggable, which is used heavily by React-Grid-Layout. This means that we can move back to the 1.x branch as the breaking change is removed.
1 parent d423898 commit 729d96d

File tree

5 files changed

+61
-5
lines changed

5 files changed

+61
-5
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ render() {
4343

4444
### Props
4545

46-
These props apply to both `<Resizable>` and `<ResizableBox>`.
46+
These props apply to both `<Resizable>` and `<ResizableBox>`. Unknown props that are not in the list below will be passed to the child component.
4747

4848
```js
4949
{

__tests__/Resizable.test.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ describe('render Resizable', () => {
1010
const props = {
1111
axis: 'both',
1212
className: 'test-classname',
13+
draggableOpts: {},
1314
handleSize: [20, 20],
1415
height: 50,
1516
lockAspectRatio: false,
1617
maxConstraints: [Infinity, Infinity],
1718
minConstraints: [20, 20],
1819
onResize: jest.fn(),
20+
onResizeStart: jest.fn(),
21+
onResizeStop: jest.fn(),
1922
resizeHandles: ['se', 'e'],
2023
transformScale: 1,
2124
width: 50,
@@ -64,6 +67,29 @@ describe('render Resizable', () => {
6467
});
6568
});
6669

70+
describe('<Resizable> props filtering', () => {
71+
const allProps = {
72+
...props,
73+
draggableOpts: {},
74+
handle: <div />,
75+
};
76+
77+
// Ensure everything in propTypes is represented here. Otherwise the next two tests are not valid
78+
test('all intended props are in our allProps object', () => {
79+
expect(['children', ...Object.keys(allProps)].sort()).toEqual(Object.keys(Resizable.propTypes).sort());
80+
});
81+
82+
test('none of these props leak down to the child', () => {
83+
const element = shallow(<Resizable {...allProps}><div className="foo" /></Resizable>);
84+
expect(Object.keys(element.find('.foo').props())).toEqual(['className', 'children']);
85+
});
86+
87+
test('className is constructed properly', () => {
88+
const element = shallow(<Resizable {...allProps}><div className="foo" /></Resizable>);
89+
expect(element.find('.foo').props().className).toEqual(`foo ${allProps.className} react-resizable`);
90+
});
91+
});
92+
6793
describe('onResize callback with modified position', () => {
6894
const customProps = {
6995
...props,

__tests__/ResizableBox.test.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Resizable from "../lib/Resizable";
99
describe('render ResizableBox', () => {
1010
const props = {
1111
axis: 'x',
12+
draggableOpts: {},
1213
handle: jest.fn(resizeHandle => <span className={`test-class-${resizeHandle}`} />),
1314
handleSize: [20, 20],
1415
height: 50,
@@ -19,6 +20,7 @@ describe('render ResizableBox', () => {
1920
onResizeStart: jest.fn(),
2021
onResizeStop: jest.fn(),
2122
resizeHandles: ['w'],
23+
transformScale: 1,
2224
width: 50,
2325
};
2426
const children = <span className="children" />;
@@ -61,6 +63,23 @@ describe('render ResizableBox', () => {
6163
expect(props.onResizeStop).toHaveBeenCalledWith(fakeEvent, data);
6264
});
6365

66+
describe('<Resizable> props filtering', () => {
67+
// Ensure everything in propTypes is represented here. Otherwise the next two tests are not valid
68+
test('all intended props are in our props object', () => {
69+
expect(['children', 'className', ...Object.keys(props)].sort()).toEqual(Object.keys(Resizable.propTypes).sort());
70+
});
71+
72+
test('none of these props leak down to the child', () => {
73+
const element = shallow(<ResizableBox {...props} />);
74+
expect(Object.keys(element.find('div').props())).toEqual(['style']);
75+
});
76+
77+
test('className is constructed properly', () => {
78+
const element = shallow(<ResizableBox {...props} className='foo' />);
79+
expect(element.find('div').props().className).toEqual(`foo`);
80+
});
81+
});
82+
6483
test('style prop', () => {
6584
const element = shallow(<ResizableBox {...props} style={{backgroundColor: 'red'}}>{children}</ResizableBox>);
6685
expect(element.find('div').at(0).prop('style')).toEqual({

lib/Resizable.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,18 @@ export default class Resizable extends React.Component<Props, ResizableState> {
163163
}
164164

165165
render(): ReactNode {
166-
const {children, draggableOpts, resizeHandles, className} = this.props;
166+
// Pass along only props not meant for the `<Resizable>`.`
167+
// eslint-disable-next-line no-unused-vars
168+
const {children, className, draggableOpts, width, height, handle, handleSize,
169+
lockAspectRatio, axis, minConstraints, maxConstraints, onResize,
170+
onResizeStop, onResizeStart, resizeHandles, transformScale, ...p} = this.props;
167171

168172
// What we're doing here is getting the child of this element, and cloning it with this element's props.
169173
// We are then defining its children as:
170174
// Its original children (resizable's child's children), and
171175
// One or more draggable handles.
172176
return cloneElement(children, {
177+
...p,
173178
className: `${className ? `${className} ` : ''}react-resizable`,
174179
children: [
175180
...children.props.children,

lib/ResizableBox.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// @flow
22
import * as React from 'react';
3-
import type {Node as ReactNode} from 'react';
3+
import type {Node as ReactNode, Element as ReactElement} from 'react';
4+
import PropTypes from 'prop-types';
45

56
import Resizable from './Resizable';
67
import {resizableProps} from "./propTypes";
@@ -10,10 +11,15 @@ import type {ResizeCallbackData, ResizableBoxState} from './propTypes';
1011
// <ResizableBox> does not have defaultProps, so we can use this type to tell Flow that we don't
1112
// care about that and will handle it in <Resizable> instead.
1213
// A <ResizableBox> can also have a `style` property.
13-
type ResizableBoxProps = {|...React.ElementConfig<typeof Resizable>, style?: Object|};
14+
type ResizableBoxProps = {|...React.ElementConfig<typeof Resizable>, style?: Object, children?: ReactElement<any>|};
1415

1516
export default class ResizableBox extends React.Component<ResizableBoxProps, ResizableBoxState> {
16-
static propTypes = resizableProps;
17+
18+
// PropTypes are identical to <Resizable>, except that children are not strictly required to be present.
19+
static propTypes = {
20+
...resizableProps,
21+
children: PropTypes.element,
22+
};
1723

1824
state: ResizableBoxState = {
1925
width: this.props.width,

0 commit comments

Comments
 (0)