Skip to content

Commit d2ec5c4

Browse files
authored
Merge pull request #82 from zombieJ/stretch
Support stretch porp
2 parents 8717fb6 + 33e17d5 commit d2ec5c4

File tree

5 files changed

+187
-25
lines changed

5 files changed

+187
-25
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,12 @@ ReactDOM.render((
233233
<td></td>
234234
<td>builtin placement align map. used by placement prop</td>
235235
</tr>
236+
<tr>
237+
<td>stretch</td>
238+
<td>string</td>
239+
<td></td>
240+
<td>Let popup div stretch with trigger element. enums of 'width', 'minWidth', 'height', 'minHeight'. (You can also mixed with 'height minWidth')</td>
241+
</tr>
236242
</tbody>
237243
</table>
238244

examples/simple.js

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class Test extends React.Component {
6060
},
6161
offsetX: undefined,
6262
offsetY: undefined,
63+
stretch: '',
6364
};
6465

6566
onPlacementChange = (e) => {
@@ -68,6 +69,12 @@ class Test extends React.Component {
6869
});
6970
}
7071

72+
onStretch = (e) => {
73+
this.setState({
74+
stretch: e.target.value,
75+
});
76+
}
77+
7178
onTransitionChange = (e) => {
7279
this.setState({
7380
transitionName: e.target.checked ? e.target.value : '',
@@ -150,6 +157,17 @@ class Test extends React.Component {
150157
</select>
151158
</label>
152159
&nbsp;&nbsp;&nbsp;&nbsp;
160+
<label>
161+
Stretch:
162+
<select value={state.stretch} onChange={this.onStretch}>
163+
<option value="">--NONE--</option>
164+
<option value="width">width</option>
165+
<option value="minWidth">minWidth</option>
166+
<option value="height">height</option>
167+
<option value="minHeight">minHeight</option>
168+
</select>
169+
</label>
170+
&nbsp;&nbsp;&nbsp;&nbsp;
153171
<label>
154172
<input
155173
value="rc-trigger-popup-zoom"
@@ -251,7 +269,7 @@ class Test extends React.Component {
251269
&nbsp;&nbsp;&nbsp;&nbsp;
252270
<button onClick={this.destroy}>destroy</button>
253271
</div>
254-
<div style={{ margin: 100, position: 'relative' }}>
272+
<div style={{ margin: 120, position: 'relative' }}>
255273
<Trigger
256274
getPopupContainer={undefined && getPopupContainer}
257275
popupAlign={getPopupAlign(state)}
@@ -260,19 +278,34 @@ class Test extends React.Component {
260278
// zIndex={40}
261279
mask={this.state.mask}
262280
maskClosable={this.state.maskClosable}
281+
stretch={this.state.stretch}
263282
// maskAnimation="fade"
264283
// mouseEnterDelay={0.1}
265284
// mouseLeaveDelay={0.1}
266285
action={Object.keys(state.trigger)}
267286
builtinPlacements={builtinPlacements}
287+
popupStyle={{
288+
border: '1px solid red',
289+
padding: 10,
290+
background: 'white',
291+
boxSizing: 'border-box',
292+
}}
268293
popup={
269-
<div style={{ border: '1px solid red', padding: 10, background: 'white' }}>
294+
<div>
270295
i am a popup
271296
</div>
272297
}
273298
popupTransitionName={state.transitionName}
274299
>
275-
<a href="#" style={{ margin: 20 }} onClick={preventDefault}>trigger</a>
300+
<a
301+
style={{ margin: 20, display: 'inline-block', background: `rgba(255, 0, 0, 0.05)` }}
302+
href="#"
303+
onClick={preventDefault}
304+
>
305+
<p>This is a example of trigger usage.</p>
306+
<p>You can adjust the value above</p>
307+
<p>which will also change the behaviour of popup.</p>
308+
</a>
276309
</Trigger>
277310
</div>
278311
</div>);

src/Popup.js

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,31 @@ class Popup extends Component {
2020
className: PropTypes.string,
2121
prefixCls: PropTypes.string,
2222
onMouseLeave: PropTypes.func,
23+
stretch: PropTypes.string,
24+
children: PropTypes.node,
2325
};
2426

2527
constructor(props) {
2628
super(props);
2729

30+
this.state = {
31+
// Used for stretch
32+
stretchChecked: false,
33+
targetWidth: undefined,
34+
targetHeight: undefined,
35+
};
36+
2837
this.savePopupRef = saveRef.bind(this, 'popupInstance');
2938
this.saveAlignRef = saveRef.bind(this, 'alignInstance');
3039
}
3140

3241
componentDidMount() {
3342
this.rootNode = this.getPopupDomNode();
43+
this.setStretchSize();
44+
}
45+
46+
componentDidUpdate() {
47+
this.setStretchSize();
3448
}
3549

3650
onAlign = (popupDomNode, align) => {
@@ -45,6 +59,33 @@ class Popup extends Component {
4559
props.onAlign(popupDomNode, align);
4660
}
4761

62+
// Record size if stretch needed
63+
setStretchSize = () => {
64+
const { stretch, getRootDomNode, visible } = this.props;
65+
const { stretchChecked, targetHeight, targetWidth } = this.state;
66+
67+
if (!stretch || !visible) {
68+
if (stretchChecked) {
69+
this.setState({ stretchChecked: false });
70+
}
71+
return;
72+
}
73+
74+
const $ele = getRootDomNode();
75+
if (!$ele) return;
76+
77+
const height = $ele.offsetHeight;
78+
const width = $ele.offsetWidth;
79+
80+
if (targetHeight !== height || targetWidth !== width || !stretchChecked) {
81+
this.setState({
82+
stretchChecked: true,
83+
targetHeight: height,
84+
targetWidth: width,
85+
});
86+
}
87+
};
88+
4889
getPopupDomNode() {
4990
return ReactDOM.findDOMNode(this.popupInstance);
5091
}
@@ -77,24 +118,54 @@ class Popup extends Component {
77118
}
78119

79120
getPopupElement() {
80-
const { savePopupRef, props } = this;
81-
const { align, style, visible, prefixCls, destroyPopupOnHide } = props;
121+
const { savePopupRef } = this;
122+
const { stretchChecked, targetHeight, targetWidth } = this.state;
123+
const {
124+
align, visible,
125+
prefixCls, style, getClassNameFromAlign,
126+
destroyPopupOnHide, stretch, children,
127+
onMouseEnter, onMouseLeave,
128+
} = this.props;
82129
const className = this.getClassName(this.currentAlignClassName ||
83-
props.getClassNameFromAlign(align));
130+
getClassNameFromAlign(align));
84131
const hiddenClassName = `${prefixCls}-hidden`;
132+
85133
if (!visible) {
86134
this.currentAlignClassName = null;
87135
}
136+
137+
const sizeStyle = {};
138+
if (stretch) {
139+
if (stretchChecked) {
140+
// Stretch with target
141+
if (stretch.indexOf('height') !== -1) {
142+
sizeStyle.height = targetHeight;
143+
} else if (stretch.indexOf('minHeight') !== -1) {
144+
sizeStyle.minHeight = targetHeight;
145+
}
146+
if (stretch.indexOf('width') !== -1) {
147+
sizeStyle.width = targetWidth;
148+
} else if (stretch.indexOf('minWidth') !== -1) {
149+
sizeStyle.minWidth = targetWidth;
150+
}
151+
} else {
152+
// Do nothing when stretch not ready
153+
return null;
154+
}
155+
}
156+
88157
const newStyle = {
158+
...sizeStyle,
89159
...style,
90160
...this.getZIndexStyle(),
91161
};
162+
92163
const popupInnerProps = {
93164
className,
94165
prefixCls,
95166
ref: savePopupRef,
96-
onMouseEnter: props.onMouseEnter,
97-
onMouseLeave: props.onMouseLeave,
167+
onMouseEnter,
168+
onMouseLeave,
98169
style: newStyle,
99170
};
100171
if (destroyPopupOnHide) {
@@ -118,7 +189,7 @@ class Popup extends Component {
118189
visible
119190
{...popupInnerProps}
120191
>
121-
{props.children}
192+
{children}
122193
</PopupInner>
123194
</Align>
124195
) : null}
@@ -148,7 +219,7 @@ class Popup extends Component {
148219
hiddenClassName={hiddenClassName}
149220
{...popupInnerProps}
150221
>
151-
{props.children}
222+
{children}
152223
</PopupInner>
153224
</Align>
154225
</Animate>

src/index.js

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export default class Trigger extends React.Component {
6767
PropTypes.object,
6868
]),
6969
maskAnimation: PropTypes.string,
70+
stretch: PropTypes.string,
7071
};
7172

7273
static defaultProps = {
@@ -323,36 +324,46 @@ export default class Trigger extends React.Component {
323324
}
324325

325326
getComponent = () => {
326-
const { props, state } = this;
327+
const {
328+
prefixCls, destroyPopupOnHide, popupClassName, action,
329+
onPopupAlign, popupAnimation, popupTransitionName, popupStyle,
330+
mask, maskAnimation, maskTransitionName, zIndex, popup, stretch,
331+
} = this.props;
332+
const { state } = this;
333+
334+
const align = this.getPopupAlign();
335+
327336
const mouseProps = {};
328337
if (this.isMouseEnterToShow()) {
329338
mouseProps.onMouseEnter = this.onPopupMouseEnter;
330339
}
331340
if (this.isMouseLeaveToHide()) {
332341
mouseProps.onMouseLeave = this.onPopupMouseLeave;
333342
}
343+
334344
return (
335345
<Popup
336-
prefixCls={props.prefixCls}
337-
destroyPopupOnHide={props.destroyPopupOnHide}
346+
prefixCls={prefixCls}
347+
destroyPopupOnHide={destroyPopupOnHide}
338348
visible={state.popupVisible}
339-
className={props.popupClassName}
340-
action={props.action}
341-
align={this.getPopupAlign()}
342-
onAlign={props.onPopupAlign}
343-
animation={props.popupAnimation}
349+
className={popupClassName}
350+
action={action}
351+
align={align}
352+
onAlign={onPopupAlign}
353+
animation={popupAnimation}
344354
getClassNameFromAlign={this.getPopupClassNameFromAlign}
345355
{...mouseProps}
356+
stretch={stretch}
346357
getRootDomNode={this.getRootDomNode}
347-
style={props.popupStyle}
348-
mask={props.mask}
349-
zIndex={props.zIndex}
350-
transitionName={props.popupTransitionName}
351-
maskAnimation={props.maskAnimation}
352-
maskTransitionName={props.maskTransitionName}
358+
style={popupStyle}
359+
mask={mask}
360+
zIndex={zIndex}
361+
transitionName={popupTransitionName}
362+
maskAnimation={maskAnimation}
363+
maskTransitionName={maskTransitionName}
353364
ref={this.savePopup}
354365
>
355-
{typeof props.popup === 'function' ? props.popup() : props.popup}
366+
{typeof popup === 'function' ? popup() : popup}
356367
</Popup>
357368
);
358369
}

tests/index.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,4 +727,45 @@ describe('rc-trigger', function main() {
727727
expect(mock.testInstance).to.be('bar');
728728
});
729729
});
730+
731+
describe.only('stretch', () => {
732+
const createTrigger = (stretch) => ReactDOM.render((
733+
<Trigger
734+
action={['click']}
735+
popupAlign={placementAlignMap.left}
736+
popup={<strong className="x-content">tooltip2</strong>}
737+
stretch={stretch}
738+
>
739+
<div className="target">
740+
click me to show trigger
741+
<br />
742+
react component trigger
743+
</div>
744+
</Trigger>
745+
), div);
746+
747+
it('width', (done) => {
748+
const trigger = createTrigger('width');
749+
const domNode = ReactDOM.findDOMNode(trigger);
750+
Simulate.click(domNode);
751+
752+
async.series([timeout(20), (next) => {
753+
const popupDomNode = trigger.getPopupDomNode();
754+
expect($(popupDomNode).width()).to.be($(domNode).width());
755+
next();
756+
}], done);
757+
});
758+
759+
it('height', (done) => {
760+
const trigger = createTrigger('height');
761+
const domNode = ReactDOM.findDOMNode(trigger);
762+
Simulate.click(domNode);
763+
764+
async.series([timeout(20), (next) => {
765+
const popupDomNode = trigger.getPopupDomNode();
766+
expect($(popupDomNode).height()).to.be($(domNode).height());
767+
next();
768+
}], done);
769+
});
770+
});
730771
});

0 commit comments

Comments
 (0)