Skip to content

Commit 205e470

Browse files
committed
feat: Support forceRender
1 parent aea47a3 commit 205e470

File tree

3 files changed

+55
-7
lines changed

3 files changed

+55
-7
lines changed

examples/CSSMotion.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import './CSSMotion.less';
55

66
interface DemoState {
77
show: boolean;
8+
forceRender: boolean;
89
motionLeaveImmediately: boolean;
910
removeOnLeave: boolean;
1011
hasMotionClassName: boolean;
1112
prepare: boolean;
1213
}
1314

1415
async function forceDelay(): Promise<void> {
15-
return new Promise((resolve) => {
16+
return new Promise(resolve => {
1617
setTimeout(resolve, 2000);
1718
});
1819
}
@@ -32,6 +33,7 @@ const Div = React.forwardRef<HTMLDivElement, any>((props, ref) => {
3233
class Demo extends React.Component<{}, DemoState> {
3334
state: DemoState = {
3435
show: true,
36+
forceRender: false,
3537
motionLeaveImmediately: false,
3638
removeOnLeave: true,
3739
hasMotionClassName: true,
@@ -48,6 +50,10 @@ class Demo extends React.Component<{}, DemoState> {
4850
this.setState(({ prepare }) => ({ prepare: !prepare }));
4951
};
5052

53+
onForceRender = () => {
54+
this.setState(({ forceRender }) => ({ forceRender: !forceRender }));
55+
};
56+
5157
onRemoveOnLeave = () => {
5258
this.setState(({ removeOnLeave }) => ({ removeOnLeave: !removeOnLeave }));
5359
};
@@ -84,6 +90,7 @@ class Demo extends React.Component<{}, DemoState> {
8490
render() {
8591
const {
8692
show,
93+
forceRender,
8794
motionLeaveImmediately,
8895
removeOnLeave,
8996
hasMotionClassName,
@@ -106,6 +113,15 @@ class Demo extends React.Component<{}, DemoState> {
106113
hasMotionClassName
107114
</label>
108115

116+
<label>
117+
<input
118+
type="checkbox"
119+
onChange={this.onForceRender}
120+
checked={forceRender}
121+
/>{' '}
122+
forceRender
123+
</label>
124+
109125
<label>
110126
<input
111127
type="checkbox"
@@ -130,6 +146,7 @@ class Demo extends React.Component<{}, DemoState> {
130146
<h2>With Transition Class</h2>
131147
<CSSMotion
132148
visible={show}
149+
forceRender={forceRender}
133150
motionName={hasMotionClassName ? 'transition' : null}
134151
removeOnLeave={removeOnLeave}
135152
leavedClassName="hidden"
@@ -140,7 +157,7 @@ class Demo extends React.Component<{}, DemoState> {
140157
onLeaveActive={this.onCollapse}
141158
onEnterEnd={this.skipColorTransition}
142159
onLeaveEnd={this.skipColorTransition}
143-
onVisibleChanged={(visible) => {
160+
onVisibleChanged={visible => {
144161
console.log('Visible Changed:', visible);
145162
}}
146163
>
@@ -158,6 +175,7 @@ class Demo extends React.Component<{}, DemoState> {
158175
<h2>With Animation Class</h2>
159176
<CSSMotion
160177
visible={show}
178+
forceRender={forceRender}
161179
motionName={hasMotionClassName ? 'animation' : null}
162180
removeOnLeave={removeOnLeave}
163181
leavedClassName="hidden"

src/CSSMotion.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,17 @@ export interface CSSMotionProps {
4545
motionLeave?: boolean;
4646
motionLeaveImmediately?: boolean;
4747
motionDeadline?: number;
48+
/**
49+
* Create element in view even the element is invisible.
50+
* Will patch `display: none` style on it.
51+
*/
52+
forceRender?: boolean;
53+
/**
54+
* Remove element when motion end. This will not work when `forceRender` is set.
55+
*/
4856
removeOnLeave?: boolean;
4957
leavedClassName?: string;
58+
/** @private Used by CSSMotionList. Do not use in your production. */
5059
eventProps?: object;
5160

5261
// Prepare groups
@@ -114,6 +123,7 @@ export function genCSSMotion(
114123
visible = true,
115124
removeOnLeave = true,
116125

126+
forceRender,
117127
children,
118128
motionName,
119129
leavedClassName,
@@ -170,6 +180,11 @@ export function genCSSMotion(
170180
{ ...eventProps, className: leavedClassName },
171181
setNodeRef,
172182
);
183+
} else if (forceRender) {
184+
motionChildren = children(
185+
{ ...eventProps, style: { display: 'none' } },
186+
setNodeRef,
187+
);
173188
} else {
174189
motionChildren = null;
175190
}

tests/CSSMotion.spec.tsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,7 @@ describe('CSSMotion', () => {
246246
});
247247
}
248248

249-
test(
250-
'without ref',
251-
React.forwardRef((props) => <div {...props} />),
252-
);
249+
test('without ref', React.forwardRef(props => <div {...props} />));
253250

254251
test(
255252
'FC with ref',
@@ -509,7 +506,7 @@ describe('CSSMotion', () => {
509506
let lockResolve: Function;
510507
const onAppearPrepare = jest.fn(
511508
() =>
512-
new Promise((resolve) => {
509+
new Promise(resolve => {
513510
lockResolve = resolve;
514511
}),
515512
);
@@ -545,4 +542,22 @@ describe('CSSMotion', () => {
545542
wrapper.find('.motion-box').hasClass('bamboo-appear-prepare'),
546543
).toBeFalsy();
547544
});
545+
546+
it('forceRender', () => {
547+
const wrapper = mount(
548+
<CSSMotion forceRender motionName="bamboo" visible={false}>
549+
{({ style, className }) => (
550+
<div style={style} className={classNames('motion-box', className)} />
551+
)}
552+
</CSSMotion>,
553+
);
554+
555+
expect(wrapper.find('.motion-box').props().style).toEqual({
556+
display: 'none',
557+
});
558+
559+
// Reset should hide
560+
wrapper.setProps({ forceRender: false });
561+
expect(wrapper.find('.motion-box')).toHaveLength(0);
562+
});
548563
});

0 commit comments

Comments
 (0)