Skip to content

Commit 43adf52

Browse files
committed
fix: motion lock
1 parent a5e8915 commit 43adf52

File tree

6 files changed

+72
-36
lines changed

6 files changed

+72
-36
lines changed

docs/examples/multiple-Portal.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,19 @@ const Demo: React.FC = () => {
4646
<button type="button" onClick={onToggleDialog}>
4747
open dialog
4848
</button>
49+
<button
50+
type="button"
51+
onClick={() => {
52+
setShowDialog(true);
53+
setTimeout(() => {
54+
setShowDialog(false);
55+
}, 0);
56+
}}
57+
>
58+
quick
59+
</button>
4960
{dialog}
50-
{/* {drawer} */}
61+
{drawer}
5162
</div>
5263
);
5364
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"@rc-component/portal": "^1.0.0-8",
5353
"@rc-component/util": "^1.0.1",
5454
"classnames": "^2.2.6",
55-
"@rc-component/motion": "^1.1.0"
55+
"@rc-component/motion": "^1.1.3"
5656
},
5757
"devDependencies": {
5858
"@rc-component/father-plugin": "^2.0.2",

src/Dialog/Content/Panel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ export interface PanelProps extends Omit<IDialogPropTypes, 'getOpenCount'> {
1717
holderRef?: React.Ref<HTMLDivElement>;
1818
}
1919

20-
export type ContentRef = {
20+
export type PanelRef = {
2121
focus: () => void;
2222
changeActive: (next: boolean) => void;
2323
};
2424

25-
const Panel = React.forwardRef<ContentRef, PanelProps>((props, ref) => {
25+
const Panel = React.forwardRef<PanelRef, PanelProps>((props, ref) => {
2626
const {
2727
prefixCls,
2828
className,

src/Dialog/Content/index.tsx

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ import { useRef } from 'react';
33
import classNames from 'classnames';
44
import CSSMotion from '@rc-component/motion';
55
import { offset } from '../../util';
6-
import type { PanelProps, ContentRef } from './Panel';
6+
import type { PanelProps, PanelRef } from './Panel';
77
import Panel from './Panel';
88

9-
console.log(CSSMotion);
9+
export type ContentRef = PanelRef & {
10+
inMotion: () => boolean;
11+
enableMotion: () => boolean;
12+
};
1013

1114
export type ContentProps = {
1215
motionName: string;
@@ -34,6 +37,15 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
3437
inMotion: () => boolean;
3538
}>();
3639

40+
const panelRef = useRef<PanelRef>();
41+
42+
// ============================== Refs ==============================
43+
React.useImperativeHandle(ref, () => ({
44+
...panelRef.current,
45+
inMotion: dialogRef.current.inMotion,
46+
enableMotion: dialogRef.current.enableMotion,
47+
}));
48+
3749
// ============================= Style ==============================
3850
const [transformOrigin, setTransformOrigin] = React.useState<string>();
3951
const contentStyle: React.CSSProperties = {};
@@ -43,8 +55,7 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
4355
}
4456

4557
function onPrepare() {
46-
console.log('onPrepare', dialogRef.current);
47-
const elementOffset = offset(dialogRef.current?.nativeElement);
58+
const elementOffset = offset(dialogRef.current.nativeElement);
4859

4960
setTransformOrigin(
5061
mousePosition && (mousePosition.x || mousePosition.y)
@@ -53,12 +64,6 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
5364
);
5465
}
5566

56-
const bbb = React.useCallback((aaa) => {
57-
console.log('???', aaa);
58-
dialogRef.current = aaa;
59-
}, []);
60-
console.log('render....');
61-
6267
// ============================= Render =============================
6368
return (
6469
<CSSMotion
@@ -69,12 +74,12 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
6974
forceRender={forceRender}
7075
motionName={motionName}
7176
removeOnLeave={destroyOnClose}
72-
ref={bbb}
77+
ref={dialogRef}
7378
>
7479
{({ className: motionClassName, style: motionStyle }, motionRef) => (
7580
<Panel
7681
{...props}
77-
ref={ref}
82+
ref={panelRef}
7883
title={title}
7984
ariaId={ariaId}
8085
prefixCls={prefixCls}

src/Dialog/index.tsx

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import * as React from 'react';
77
import { useEffect, useRef } from 'react';
88
import type { IDialogPropTypes } from '../IDialogPropTypes';
99
import { getMotionName } from '../util';
10-
import Content from './Content';
11-
import type { ContentRef } from './Content/Panel';
10+
import Content, { type ContentRef } from './Content';
1211
import Mask from './Mask';
1312
import { warning } from '@rc-component/util/lib/warning';
1413

@@ -78,27 +77,35 @@ const Dialog: React.FC<IDialogPropTypes> = (props) => {
7877
}
7978

8079
// ========================= Events =========================
80+
// Close action will trigger by:
81+
// 1. When hide motion end
82+
// 2. Controlled `open` to `false` immediately after set to `true` which will not trigger motion
83+
function doClose() {
84+
// Clean up scroll bar & focus back
85+
setAnimatedVisible(false);
86+
87+
if (mask && lastOutSideActiveElementRef.current && focusTriggerAfterClose) {
88+
try {
89+
lastOutSideActiveElementRef.current.focus({ preventScroll: true });
90+
} catch (e) {
91+
// Do nothing
92+
}
93+
lastOutSideActiveElementRef.current = null;
94+
}
95+
96+
// Trigger afterClose only when change visible from true to false
97+
if (animatedVisible) {
98+
afterClose?.();
99+
}
100+
}
101+
81102
function onDialogVisibleChanged(newVisible: boolean) {
82103
// Try to focus
83104
if (newVisible) {
84105
focusDialogContent();
85106
} else {
86-
// Clean up scroll bar & focus back
87-
setAnimatedVisible(false);
88-
89-
if (mask && lastOutSideActiveElementRef.current && focusTriggerAfterClose) {
90-
try {
91-
lastOutSideActiveElementRef.current.focus({ preventScroll: true });
92-
} catch (e) {
93-
// Do nothing
94-
}
95-
lastOutSideActiveElementRef.current = null;
96-
}
97-
98-
// Trigger afterClose only when change visible from true to false
99-
if (animatedVisible) {
100-
afterClose?.();
101-
}
107+
console.log('hide???');
108+
doClose();
102109
}
103110
afterOpenChange?.(newVisible);
104111
}
@@ -154,6 +161,12 @@ const Dialog: React.FC<IDialogPropTypes> = (props) => {
154161
if (visible) {
155162
setAnimatedVisible(true);
156163
saveLastOutSideActiveElementRef();
164+
} else if (
165+
animatedVisible &&
166+
contentRef.current.enableMotion() &&
167+
!contentRef.current.inMotion()
168+
) {
169+
doClose();
157170
}
158171
}, [visible]);
159172

tests/index.spec.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,10 +515,17 @@ describe('dialog', () => {
515515
const afterClose = jest.fn();
516516

517517
const { rerender } = render(<Dialog afterClose={afterClose} visible />);
518-
jest.runAllTimers();
518+
act(() => {
519+
jest.runAllTimers();
520+
});
519521

522+
console.log('~~~~~~false~~~~~~');
520523
rerender(<Dialog afterClose={afterClose} visible={false} />);
521-
jest.runAllTimers();
524+
console.log('~~~~~~111~~~~~~');
525+
act(() => {
526+
jest.runAllTimers();
527+
});
528+
console.log('~~~~~~222~~~~~~');
522529

523530
expect(afterClose).toHaveBeenCalledTimes(1);
524531
});

0 commit comments

Comments
 (0)