Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/examples/multiple-Portal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ const Demo: React.FC = () => {
<button type="button" onClick={onToggleDialog}>
open dialog
</button>
<button
type="button"
onClick={() => {
setShowDialog(true);
setTimeout(() => {
setShowDialog(false);
}, 0);
}}
>
quick
</button>
{dialog}
{drawer}
</div>
Expand Down
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"lint:tsc": "tsc -p tsconfig.json --noEmit",
"now-build": "npm run docs:build",
"prepare": "husky install",
"prepublishOnly": "npm run compile && np --yolo --no-publish",
"prepublishOnly": "npm run compile && rc-np",
"prettier": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
"start": "dumi dev",
"test": "rc-test"
Expand All @@ -49,14 +49,14 @@
]
},
"dependencies": {
"@babel/runtime": "^7.10.1",
"@rc-component/portal": "^1.0.0-8",
"@rc-component/util": "^1.0.1",
"classnames": "^2.2.6",
"rc-motion": "^2.3.0"
"@rc-component/motion": "^1.1.3"
},
"devDependencies": {
"@rc-component/father-plugin": "^2.0.1",
"@rc-component/father-plugin": "^2.0.2",
"@rc-component/np": "^1.0.3",
"@testing-library/jest-dom": "^6.1.6",
"@testing-library/react": "^13.0.0",
"@types/jest": "^29.4.0",
Expand All @@ -77,7 +77,6 @@
"husky": "^8.0.3",
"less": "^4.1.3",
"lint-staged": "^15.2.0",
"np": "^10.0.5",
"prettier": "^3.2.1",
"rc-drawer": "^7.0.0",
"rc-select": "^14.11.0",
Expand Down
4 changes: 2 additions & 2 deletions src/Dialog/Content/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ export interface PanelProps extends Omit<IDialogPropTypes, 'getOpenCount'> {
holderRef?: React.Ref<HTMLDivElement>;
}

export type ContentRef = {
export type PanelRef = {
focus: () => void;
changeActive: (next: boolean) => void;
};

const Panel = React.forwardRef<ContentRef, PanelProps>((props, ref) => {
const Panel = React.forwardRef<PanelRef, PanelProps>((props, ref) => {
const {
prefixCls,
className,
Expand Down
27 changes: 22 additions & 5 deletions src/Dialog/Content/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import * as React from 'react';
import { useRef } from 'react';
import classNames from 'classnames';
import CSSMotion from 'rc-motion';
import CSSMotion from '@rc-component/motion';
import { offset } from '../../util';
import type { PanelProps, ContentRef } from './Panel';
import type { PanelProps, PanelRef } from './Panel';
import Panel from './Panel';

export type ContentRef = PanelRef & {
inMotion: () => boolean;
enableMotion: () => boolean;
};

export type ContentProps = {
motionName: string;
ariaId: string;
Expand All @@ -27,7 +32,19 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
mousePosition,
} = props;

const dialogRef = useRef<HTMLDivElement>();
const dialogRef = useRef<{
nativeElement: HTMLDivElement;
inMotion: () => boolean;
}>();

const panelRef = useRef<PanelRef>();

// ============================== Refs ==============================
React.useImperativeHandle(ref, () => ({
...panelRef.current,
inMotion: dialogRef.current.inMotion,
enableMotion: dialogRef.current.enableMotion,
}));

// ============================= Style ==============================
const [transformOrigin, setTransformOrigin] = React.useState<string>();
Expand All @@ -38,7 +55,7 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
}

function onPrepare() {
const elementOffset = offset(dialogRef.current);
const elementOffset = offset(dialogRef.current.nativeElement);

setTransformOrigin(
mousePosition && (mousePosition.x || mousePosition.y)
Expand All @@ -62,7 +79,7 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
{({ className: motionClassName, style: motionStyle }, motionRef) => (
<Panel
{...props}
ref={ref}
ref={panelRef}
title={title}
ariaId={ariaId}
prefixCls={prefixCls}
Expand Down
2 changes: 1 addition & 1 deletion src/Dialog/Mask.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import CSSMotion from 'rc-motion';
import CSSMotion from '@rc-component/motion';

export type MaskProps = {
prefixCls: string;
Expand Down
49 changes: 31 additions & 18 deletions src/Dialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import * as React from 'react';
import { useEffect, useRef } from 'react';
import type { IDialogPropTypes } from '../IDialogPropTypes';
import { getMotionName } from '../util';
import Content from './Content';
import type { ContentRef } from './Content/Panel';
import Content, { type ContentRef } from './Content';
import Mask from './Mask';
import { warning } from '@rc-component/util/lib/warning';

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

// ========================= Events =========================
// Close action will trigger by:
// 1. When hide motion end
// 2. Controlled `open` to `false` immediately after set to `true` which will not trigger motion
function doClose() {
// Clean up scroll bar & focus back
setAnimatedVisible(false);

if (mask && lastOutSideActiveElementRef.current && focusTriggerAfterClose) {
try {
lastOutSideActiveElementRef.current.focus({ preventScroll: true });
} catch (e) {
// Do nothing
}
lastOutSideActiveElementRef.current = null;
}

// Trigger afterClose only when change visible from true to false
if (animatedVisible) {
afterClose?.();
}
}

function onDialogVisibleChanged(newVisible: boolean) {
// Try to focus
if (newVisible) {
focusDialogContent();
} else {
// Clean up scroll bar & focus back
setAnimatedVisible(false);

if (mask && lastOutSideActiveElementRef.current && focusTriggerAfterClose) {
try {
lastOutSideActiveElementRef.current.focus({ preventScroll: true });
} catch (e) {
// Do nothing
}
lastOutSideActiveElementRef.current = null;
}

// Trigger afterClose only when change visible from true to false
if (animatedVisible) {
afterClose?.();
}
console.log('hide???');
doClose();
}
afterOpenChange?.(newVisible);
}
Expand Down Expand Up @@ -154,6 +161,12 @@ const Dialog: React.FC<IDialogPropTypes> = (props) => {
if (visible) {
setAnimatedVisible(true);
saveLastOutSideActiveElementRef();
} else if (
animatedVisible &&
contentRef.current.enableMotion() &&
!contentRef.current.inMotion()
) {
doClose();
}
}, [visible]);

Expand Down
14 changes: 9 additions & 5 deletions tests/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/* eslint-disable react/no-render-return-value, max-classes-per-file, func-names, no-console */
import { fireEvent, render, act } from '@testing-library/react';
import { Provider } from 'rc-motion';
import { Provider } from '@rc-component/motion';
import KeyCode from '@rc-component/util/lib/KeyCode';
import React, { cloneElement, useEffect } from 'react';
import type { DialogProps } from '../src';
import Dialog from '../src';

jest.mock('rc-motion', () => {
jest.mock('@rc-component/motion', () => {
const OriReact = jest.requireActual('react');
const origin = jest.requireActual('rc-motion');
const origin = jest.requireActual('@rc-component/motion');
const OriCSSMotion = origin.default;

const ProxyCSSMotion = OriReact.forwardRef((props: any, ref: any) => {
Expand Down Expand Up @@ -515,10 +515,14 @@ describe('dialog', () => {
const afterClose = jest.fn();

const { rerender } = render(<Dialog afterClose={afterClose} visible />);
jest.runAllTimers();
act(() => {
jest.runAllTimers();
});

rerender(<Dialog afterClose={afterClose} visible={false} />);
jest.runAllTimers();
act(() => {
jest.runAllTimers();
});

expect(afterClose).toHaveBeenCalledTimes(1);
});
Expand Down
2 changes: 1 addition & 1 deletion tests/ref.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable react/no-render-return-value, max-classes-per-file, func-names, no-console */
import { render } from '@testing-library/react';
import { Provider } from 'rc-motion';
import { Provider } from '@rc-component/motion';
import React from 'react';
import Dialog from '../src';

Expand Down
Loading