Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ coverage
/android/
yarn.lock
package-lock.json
pnpm-lock.yaml
.storybook
.doc

Expand All @@ -48,4 +49,4 @@ package-lock.json
.dumi/tmp
.dumi/tmp-production

bun.lockb
bun.lockb
59 changes: 28 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,34 +49,34 @@ ReactDOM.render(

### rc-dialog

| Name | Type | Default | Description | Version |
| ---------------------- | ------------------------------ | --------- | ------------------------------------------------------------------------------- | ------- |
| prefixCls | String | rc-dialog | The dialog dom node's prefixCls | |
| className | String | | additional className for dialog | |
| classNames | { header?: string; body?: string; footer?: string; mask?: string; content?: string; wrapper?: string; } | | pass className to target area | |
| styles | { header?: CSSProperties; body?: CSSProperties; footer?: CSSProperties; mask?: CSSProperties; content?: CSSProperties; wrapper?: CSSProperties; } | | pass styles to target area | |
| style | Object | {} | Root style for dialog element.Such as width, height | |
| zIndex | Number | | | |
| visible | Boolean | false | current dialog's visible status | |
| animation | String | | part of dialog animation css class name | |
| maskAnimation | String | | part of dialog's mask animation css class name | |
| transitionName | String | | dialog animation css class name | |
| maskTransitionName | String | | mask animation css class name | |
| title | String\|React.Element | | Title of the dialog | |
| footer | React.Element | | footer of the dialog | |
| closable | Boolean \| ({ closeIcon?: React.ReactNode; disabled?: boolean } & React.AriaAttributes | true | whether show close button | |
| mask | Boolean | true | whether show mask | |
| maskClosable | Boolean | true | whether click mask to close | |
| keyboard | Boolean | true | whether support press esc to close | |
| mousePosition | {x:number,y:number} | | set pageX and pageY of current mouse(it will cause transform origin to be set). | |
| onClose | function() | | called when click close button or mask | |
| afterClose | function() | | called when close animation end | |
| getContainer | function(): HTMLElement | | to determine where Dialog will be mounted | |
| destroyOnClose | Boolean | false | to unmount child compenents on onClose | |
| closeIcon | ReactNode | | specific the close icon. | |
| forceRender | Boolean | false | Create dialog dom node before dialog first show | |
| focusTriggerAfterClose | Boolean | true | focus trigger element when dialog closed | |
| modalRender | (node: ReactNode) => ReactNode | | Custom modal content render | 8.3.0 |
| Name | Type | Default | Description | Version |
| --- | --- | --- | --- | --- |
| prefixCls | String | rc-dialog | The dialog dom node's prefixCls | |
| className | String | | additional className for dialog | |
| classNames | { header?: string; body?: string; footer?: string; mask?: string; content?: string; wrapper?: string; } | | pass className to target area | |
| styles | { header?: CSSProperties; body?: CSSProperties; footer?: CSSProperties; mask?: CSSProperties; content?: CSSProperties; wrapper?: CSSProperties; } | | pass styles to target area | |
| style | Object | {} | Root style for dialog element.Such as width, height | |
| zIndex | Number | | | |
| visible | Boolean | false | current dialog's visible status | |
| animation | String | | part of dialog animation css class name | |
| maskAnimation | String | | part of dialog's mask animation css class name | |
| transitionName | String | | dialog animation css class name | |
| maskTransitionName | String | | mask animation css class name | |
| title | String\|React.Element | | Title of the dialog | |
| footer | React.Element | | footer of the dialog | |
| closable | Boolean \| ({ closeIcon?: React.ReactNode; disabled?: boolean } & React.AriaAttributes | true | whether show close button | |
| mask | Boolean | true | whether show mask | |
| maskClosable | Boolean | true | whether click mask to close | |
| keyboard | Boolean | true | whether support press esc to close | |
| mousePosition | {x:number,y:number} | | set pageX and pageY of current mouse(it will cause transform origin to be set). | |
| onClose | function() | | called when click close button or mask | |
| afterClose | function() | | called when close animation end | |
| getContainer | function(): HTMLElement | | to determine where Dialog will be mounted | |
| destroyOnHidden | Boolean | false | to unmount child compenents on onClose | |
| closeIcon | ReactNode | | specific the close icon. | |
| forceRender | Boolean | false | Create dialog dom node before dialog first show | |
| focusTriggerAfterClose | Boolean | true | focus trigger element when dialog closed | |
| modalRender | (node: ReactNode) => ReactNode | | Custom modal content render | 8.3.0 |

## Development

Expand All @@ -85,8 +85,6 @@ npm install
npm start
```



## Test Case

```
Expand All @@ -102,7 +100,6 @@ npm run coverage

open coverage/ dir


## License

rc-dialog is released under the MIT license.
10 changes: 5 additions & 5 deletions docs/examples/ant-design.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const MyControl: React.FC = () => {
const [visible2, setVisible2] = React.useState(false);
const [visible3, setVisible3] = React.useState(false);
const [width, setWidth] = React.useState(600);
const [destroyOnClose, setDestroyOnClose] = React.useState(false);
const [destroyOnHidden, setDestroyOnHidden] = React.useState(false);
const [center, setCenter] = React.useState(false);
const [mousePosition, setMousePosition] = React.useState({ x: null, y: null });
const [useIcon, setUseIcon] = React.useState(false);
Expand Down Expand Up @@ -60,8 +60,8 @@ const MyControl: React.FC = () => {
setVisible3(false);
};

const onDestroyOnCloseChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setDestroyOnClose(e.target.checked);
const onDestroyOnHiddenChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setDestroyOnHidden(e.target.checked);
};

const onForceRenderChange = (e: React.ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -97,7 +97,7 @@ const MyControl: React.FC = () => {
style={style}
title="dialog1"
mousePosition={mousePosition}
destroyOnClose={destroyOnClose}
destroyOnHidden={destroyOnHidden}
closeIcon={useIcon ? getSvg(clearPath, {}, true) : undefined}
forceRender={forceRender}
focusTriggerAfterClose={false}
Expand Down Expand Up @@ -211,7 +211,7 @@ const MyControl: React.FC = () => {
&nbsp;
<label>
destroy on close:
<input type="checkbox" checked={destroyOnClose} onChange={onDestroyOnCloseChange} />
<input type="checkbox" checked={destroyOnHidden} onChange={onDestroyOnHiddenChange} />
</label>
&nbsp;
<label>
Expand Down
10 changes: 5 additions & 5 deletions docs/examples/bootstrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const InnerRender: React.FC = () => {

const MyControl: React.FC = () => {
const [visible, setVisible] = React.useState(false);
const [destroyOnClose, setDestroyOnClose] = React.useState(false);
const [destroyOnHidden, setDestroyOnHidden] = React.useState(false);

const onClick = () => {
setVisible(true);
Expand All @@ -21,14 +21,14 @@ const MyControl: React.FC = () => {
setVisible(false);
};

const onDestroyOnCloseChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setDestroyOnClose(e.target.checked);
const onDestroyOnHiddenChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setDestroyOnHidden(e.target.checked);
};

const dialog = (
<Dialog
visible={visible}
destroyOnClose={destroyOnClose}
destroyOnHidden={destroyOnHidden}
animation="slide-fade"
maskAnimation="fade"
onClose={onClose}
Expand Down Expand Up @@ -121,7 +121,7 @@ const MyControl: React.FC = () => {
&nbsp;
<label>
destroy on close:
<input type="checkbox" checked={destroyOnClose} onChange={onDestroyOnCloseChange} />
<input type="checkbox" checked={destroyOnHidden} onChange={onDestroyOnHiddenChange} />
</label>
</p>
{dialog}
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,16 @@
},
"devDependencies": {
"@rc-component/drawer": "^1.0.0",
"@rc-component/select": "^1.0.0",
"@rc-component/father-plugin": "^2.0.2",
"@rc-component/np": "^1.0.3",
"@rc-component/select": "^1.0.0",
"@testing-library/jest-dom": "^6.1.6",
"@testing-library/react": "^13.0.0",
"@types/jest": "^29.4.0",
"@types/keyv": "3.1.4",
"@types/react": "^18.0.24",
"@types/react-dom": "^18.0.8",
"@types/node": "^22.15.18",
"@types/react": "^19.1.4",
"@types/react-dom": "^19.1.5",
"@umijs/fabric": "^3.0.0",
"bootstrap": "^4.3.1",
"cheerio": "1.0.0-rc.12",
Expand Down
16 changes: 12 additions & 4 deletions src/Dialog/Content/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,16 @@ import type { IDialogPropTypes } from '../../IDialogPropTypes';
import MemoChildren from './MemoChildren';
import pickAttrs from '@rc-component/util/lib/pickAttrs';

const sentinelStyle = { width: 0, height: 0, overflow: 'hidden', outline: 'none' };
const entityStyle = { outline: 'none' };
const sentinelStyle: React.CSSProperties = {
width: 0,
height: 0,
overflow: 'hidden',
outline: 'none',
};

const entityStyle: React.CSSProperties = {
outline: 'none',
};

export interface PanelProps extends Omit<IDialogPropTypes, 'getOpenCount'> {
prefixCls: string;
Expand Down Expand Up @@ -53,8 +61,8 @@ const Panel = React.forwardRef<PanelRef, PanelProps>((props, ref) => {

const mergedRef = useComposeRef(holderRef, panelRef);

const sentinelStartRef = useRef<HTMLDivElement>();
const sentinelEndRef = useRef<HTMLDivElement>();
const sentinelStartRef = useRef<HTMLDivElement>(null);
const sentinelEndRef = useRef<HTMLDivElement>(null);

React.useImperativeHandle(ref, () => ({
focus: () => {
Expand Down
16 changes: 7 additions & 9 deletions src/Dialog/Content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,16 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
className,
visible,
forceRender,
destroyOnClose,
destroyOnHidden,
motionName,
ariaId,
onVisibleChanged,
mousePosition,
} = props;

const dialogRef = useRef<
{
nativeElement: HTMLElement;
} & CSSMotionStateRef
>();
const dialogRef = useRef<{ nativeElement: HTMLElement } & CSSMotionStateRef>(null);

const panelRef = useRef<PanelRef>();
const panelRef = useRef<PanelRef>(null);

// ============================== Refs ==============================
React.useImperativeHandle(ref, () => ({
Expand Down Expand Up @@ -74,7 +70,7 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
onEnterPrepare={onPrepare}
forceRender={forceRender}
motionName={motionName}
removeOnLeave={destroyOnClose}
removeOnLeave={destroyOnHidden}
ref={dialogRef}
>
{({ className: motionClassName, style: motionStyle }, motionRef) => (
Expand All @@ -93,6 +89,8 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
);
});

Content.displayName = 'Content';
if (process.env.NODE_ENV !== 'production') {
Content.displayName = 'Content';
}

export default Content;
8 changes: 4 additions & 4 deletions src/Dialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ const Dialog: React.FC<IDialogPropTypes> = (props) => {
}
}

const lastOutSideActiveElementRef = useRef<HTMLElement>();
const wrapperRef = useRef<HTMLDivElement>();
const contentRef = useRef<ContentRef>();
const lastOutSideActiveElementRef = useRef<HTMLElement>(null);
const wrapperRef = useRef<HTMLDivElement>(null);
const contentRef = useRef<ContentRef>(null);

const [animatedVisible, setAnimatedVisible] = React.useState(visible);

Expand Down Expand Up @@ -115,7 +115,7 @@ const Dialog: React.FC<IDialogPropTypes> = (props) => {

// >>> Content
const contentClickRef = useRef(false);
const contentTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
const contentTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null);

// We need record content click incase content popup out of dialog
const onContentMouseDown: React.MouseEventHandler = () => {
Expand Down
6 changes: 3 additions & 3 deletions src/DialogWrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const DialogWrap: React.FC<IDialogPropTypes> = (props) => {
visible,
getContainer,
forceRender,
destroyOnClose = false,
destroyOnHidden = false,
afterClose,
panelRef,
} = props;
Expand All @@ -33,7 +33,7 @@ const DialogWrap: React.FC<IDialogPropTypes> = (props) => {
}, [visible]);

// Destroy on close will remove wrapped div
if (!forceRender && destroyOnClose && !animatedVisible) {
if (!forceRender && destroyOnHidden && !animatedVisible) {
return null;
}

Expand All @@ -47,7 +47,7 @@ const DialogWrap: React.FC<IDialogPropTypes> = (props) => {
>
<Dialog
{...props}
destroyOnClose={destroyOnClose}
destroyOnHidden={destroyOnHidden}
afterClose={() => {
afterClose?.();
setAnimatedVisible(false);
Expand Down
2 changes: 1 addition & 1 deletion src/IDialogPropTypes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type IDialogPropTypes = {
closable?: boolean | ({ closeIcon?: React.ReactNode; disabled?: boolean } & React.AriaAttributes);
maskClosable?: boolean;
visible?: boolean;
destroyOnClose?: boolean;
destroyOnHidden?: boolean;
mousePosition?: {
x: number;
y: number;
Expand Down
10 changes: 5 additions & 5 deletions tests/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ describe('dialog', () => {
expect(onClose).toHaveBeenCalledTimes(1);
});

describe('destroyOnClose', () => {
describe('destroyOnHidden', () => {
it('default is false', () => {
const { rerender } = render(
<Dialog visible>
Expand All @@ -128,8 +128,8 @@ describe('dialog', () => {
});

it('destroy on hide should unmount child components on close', () => {
const Demo = (props?: Partial<DialogProps>) => (
<Dialog destroyOnClose {...props}>
const Demo: React.FC<Partial<DialogProps>> = (props) => (
<Dialog destroyOnHidden {...props}>
<input className="test-input" />
</Dialog>
);
Expand Down Expand Up @@ -417,9 +417,9 @@ describe('dialog', () => {
});

it('should focus trigger after close dialog when contains focusable element', () => {
const Demo = () => {
const Demo: React.FC = () => {
const [visible, setVisible] = React.useState(false);
const inputRef = React.useRef(null);
const inputRef = React.useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
Expand Down
Loading