Skip to content

Commit 2493bd7

Browse files
authored
feat: bounds accept HTMLElement (#890)
1 parent 36d3506 commit 2493bd7

File tree

6 files changed

+128
-8
lines changed

6 files changed

+128
-8
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -310,13 +310,13 @@ The `cancel` property disables specifies a selector to be used to prevent drag i
310310

311311
The direction of allowed movement (dragging) allowed ('x','y','both','none').
312312

313-
#### `bounds?: string;`
313+
#### `bounds?: string; | Element`
314314

315315
Specifies movement boundaries. Accepted values:
316316
- `parent` restricts movement within the node's offsetParent
317317
(nearest node with position relative or absolute)
318-
- `window`, `body`, or
319-
- Selector, like `.fooClassName`.
318+
- `window`, `body`, Selector like `.fooClassName` or
319+
- `Element`.
320320

321321

322322
#### `enableUserSelectHack?: boolean;`

src/index.test.tsx

+38
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,44 @@ test("should clamped by selector size", async (t) => {
723723
t.is((rnd.childAt(0).childAt(0).getDOMNode() as HTMLElement).style.height, "800px");
724724
});
725725

726+
test("should clamped by boundary element size", async (t) => {
727+
const rnd = mount(
728+
<div className="target" style={{ width: "800px", height: "600px" }}>
729+
<div style={{ width: "800px", height: "600px" }}>
730+
<Rnd
731+
default={{ x: 0, y: 0, width: 100, height: 100 }}
732+
resizeHandleClasses={{
733+
top: "handler",
734+
right: "handler",
735+
bottom: "handler",
736+
left: "handler",
737+
topRight: "handler",
738+
bottomRight: "handler",
739+
bottomLeft: "handler",
740+
topLeft: "handler",
741+
}}
742+
bounds={document.querySelector(".target")!}
743+
enableResizing={{
744+
top: false,
745+
right: false,
746+
bottom: false,
747+
left: false,
748+
topRight: false,
749+
bottomRight: true,
750+
bottomLeft: false,
751+
topLeft: false,
752+
}}
753+
/>
754+
</div>
755+
</div>,
756+
{ attachTo: document.querySelector("div") },
757+
);
758+
rnd.find("div.handler").at(0).simulate("mousedown", { clientX: 0, clientY: 0 });
759+
mouseMove(1200, 1200);
760+
t.is((rnd.childAt(0).getDOMNode() as HTMLElement).style.width, "800px");
761+
t.is((rnd.childAt(0).getDOMNode() as HTMLElement).style.height, "600px");
762+
});
763+
726764
test("should get rnd updated when updatePosition invoked", async (t) => {
727765
const rnd = mount<Rnd>(<Rnd default={{ x: 100, y: 100, width: 100, height: 100 }} />);
728766
rnd.instance().updatePosition({ x: 200, y: 300 });

src/index.tsx

+7-4
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export interface Props {
129129
};
130130
size?: Size;
131131
resizeGrid?: Grid;
132-
bounds?: string;
132+
bounds?: string | Element;
133133
onMouseDown?: (e: MouseEvent) => void;
134134
onMouseUp?: (e: MouseEvent) => void;
135135
onResizeStart?: RndResizeStartCallback;
@@ -330,8 +330,10 @@ export class Rnd extends React.PureComponent<Props, State> {
330330
const right = (window.innerWidth - this.resizable.size.width * scale) / scale + left;
331331
const bottom = (window.innerHeight - this.resizable.size.height * scale) / scale + top;
332332
return this.setState({ bounds: { top, right, bottom, left } });
333-
} else {
333+
} else if (typeof this.props.bounds === "string") {
334334
boundary = document.querySelector(this.props.bounds);
335+
} else if (this.props.bounds instanceof HTMLElement) {
336+
boundary = this.props.bounds;
335337
}
336338
if (!(boundary instanceof HTMLElement) || !(parent instanceof HTMLElement)) {
337339
return;
@@ -405,8 +407,10 @@ export class Rnd extends React.PureComponent<Props, State> {
405407
boundary = document.body;
406408
} else if (this.props.bounds === "window") {
407409
boundary = window;
408-
} else {
410+
} else if (typeof this.props.bounds === "string") {
409411
boundary = document.querySelector(this.props.bounds);
412+
} else if (this.props.bounds instanceof HTMLElement) {
413+
boundary = this.props.bounds;
410414
}
411415

412416
const self = this.getSelfElement();
@@ -566,7 +570,6 @@ export class Rnd extends React.PureComponent<Props, State> {
566570
left: selfRect.left - parentLeft + scrollLeft - position.x * scale,
567571
top: selfRect.top - parentTop + scrollTop - position.y * scale,
568572
};
569-
570573
}
571574

572575
refDraggable = (c: $TODO) => {

stories/bounds/element-controlled.tsx

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from "react";
2+
import { Rnd } from "../../src";
3+
import { style, parentBoundary } from "../styles";
4+
5+
type State = {
6+
x: number;
7+
y: number;
8+
width: number;
9+
height: number;
10+
};
11+
12+
const Example: React.FC = () => {
13+
const [state, setState] = React.useState<State>({
14+
width: 200,
15+
height: 200,
16+
x: 0,
17+
y: 0,
18+
});
19+
const [boundaryElm, setBoundaryElm] = React.useState<HTMLDivElement>();
20+
return (
21+
<div style={parentBoundary} ref={(elm) => setBoundaryElm(elm!)}>
22+
<Rnd
23+
style={style}
24+
bounds={boundaryElm}
25+
size={{
26+
width: state.width,
27+
height: state.height,
28+
}}
29+
position={{
30+
x: state.x,
31+
y: state.y,
32+
}}
33+
onDragStop={(e: any, d: any) => {
34+
setState({ ...state, x: d.x, y: d.y });
35+
}}
36+
onResize={(e, direction, ref, delta, position) => {
37+
setState({
38+
width: ref.offsetWidth,
39+
height: ref.offsetHeight,
40+
...position,
41+
});
42+
}}
43+
>
44+
001
45+
</Rnd>
46+
</div>
47+
);
48+
};
49+
50+
export default Example;
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from "react";
2+
import { Rnd } from "../../src";
3+
import { style, parentBoundary } from "../styles";
4+
5+
export default () => {
6+
const [boundaryElm, setBoundaryElm] = React.useState<HTMLDivElement>();
7+
return (
8+
<div style={parentBoundary} ref={(ref) => setBoundaryElm(ref!)}>
9+
{boundaryElm && (
10+
<Rnd
11+
style={style}
12+
bounds={boundaryElm}
13+
default={{
14+
width: 200,
15+
height: 200,
16+
x: 0,
17+
y: 0,
18+
}}
19+
>
20+
001
21+
</Rnd>
22+
)}
23+
</div>
24+
);
25+
};

stories/index.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import BoundsSelectorUncontrolled from "./bounds/selector-uncontrolled";
2525
import BoundsSelectorControlled from "./bounds/selector-controlled";
2626
import BoundsWindowControlled from "./bounds/window-controlled";
2727
import BoundsBodyControlled from "./bounds/body-controlled";
28+
import BoundsElementControlled from "./bounds/element-controlled";
29+
import BoundsElementUncontrolled from "./bounds/element-uncontrolled";
2830

2931
import SizePercentUncontrolled from "./size/size-percent-uncontrolled";
3032
import SizePercentControlled from "./size/size-percent-controlled";
@@ -63,7 +65,9 @@ storiesOf("bounds", module)
6365
.add("selector uncontrolled", () => <BoundsSelectorUncontrolled />)
6466
.add("selector controlled", () => <BoundsSelectorControlled />)
6567
.add("window controlled", () => <BoundsWindowControlled />)
66-
.add("body controlled", () => <BoundsBodyControlled />);
68+
.add("body controlled", () => <BoundsBodyControlled />)
69+
.add("element controlled", () => <BoundsElementControlled />)
70+
.add("element uncontrolled", () => <BoundsElementUncontrolled />)
6771

6872
storiesOf("scale", module)
6973
.add("with parent boundary", () => <ScaleParentUnControlled />)

0 commit comments

Comments
 (0)