diff --git a/assets/index/Dialog.less b/assets/index/Dialog.less index 013bdd54..c856a7c8 100644 --- a/assets/index/Dialog.less +++ b/assets/index/Dialog.less @@ -22,6 +22,10 @@ font-weight: bold; } + &-extra { + padding-right: 36px; + } + &-section { position: relative; background-color: #ffffff; @@ -43,7 +47,7 @@ color: #000; text-shadow: 0 1px 0 #fff; filter: alpha(opacity=20); - opacity: .2; + opacity: 0.2; text-decoration: none; &:disabled { @@ -51,7 +55,7 @@ } &-x:after { - content: '×' + content: '×'; } &:hover { @@ -67,6 +71,9 @@ background: #fff; color: #666; border-bottom: 1px solid #e9e9e9; + display: flex; + align-items: center; + justify-content: space-between; } &-body { @@ -85,7 +92,8 @@ animation-fill-mode: both; } - &-zoom-enter, &-zoom-appear { + &-zoom-enter, + &-zoom-appear { opacity: 0; .effect(); animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1); @@ -98,7 +106,8 @@ animation-play-state: paused; } - &-zoom-enter&-zoom-enter-active, &-zoom-appear&-zoom-appear-active { + &-zoom-enter&-zoom-enter-active, + &-zoom-appear&-zoom-appear-active { animation-name: rcDialogZoomIn; animation-play-state: running; } @@ -120,7 +129,6 @@ } @keyframes rcDialogZoomOut { 0% { - transform: scale(1, 1); } 100% { diff --git a/docs/examples/ant-design.tsx b/docs/examples/ant-design.tsx index f3376b90..aab217b4 100644 --- a/docs/examples/ant-design.tsx +++ b/docs/examples/ant-design.tsx @@ -96,6 +96,7 @@ const MyControl: React.FC = () => { onClose={onClose} style={style} title="dialog1" + extra={click me} mousePosition={mousePosition} destroyOnHidden={destroyOnHidden} closeIcon={useIcon ? getSvg(clearPath, {}, true) : undefined} diff --git a/src/Dialog/Content/Panel.tsx b/src/Dialog/Content/Panel.tsx index e06678c4..b7c191ad 100644 --- a/src/Dialog/Content/Panel.tsx +++ b/src/Dialog/Content/Panel.tsx @@ -54,6 +54,7 @@ const Panel = React.forwardRef((props, ref) => { height, classNames: modalClassNames, styles: modalStyles, + extra, } = props; // ================================= Refs ================================= @@ -97,6 +98,15 @@ const Panel = React.forwardRef((props, ref) => { ) : null; + const extraNode = extra ? ( +
+ {extra} +
+ ) : null; + const headerNode = title ? (
((props, ref) => { > {title}
+ {extraNode} - ) : null; + ) : ( +
+ {extraNode} +
+ ); const closableObj = useMemo(() => { if (typeof closable === 'object' && closable !== null) { diff --git a/src/Dialog/Content/index.tsx b/src/Dialog/Content/index.tsx index df6a97ea..b469f610 100644 --- a/src/Dialog/Content/index.tsx +++ b/src/Dialog/Content/index.tsx @@ -30,12 +30,17 @@ const Content = React.forwardRef((props, ref) => { ariaId, onVisibleChanged, mousePosition, + extra, } = props; const dialogRef = useRef<{ nativeElement: HTMLElement } & CSSMotionStateRef>(null); const panelRef = useRef(null); + const hasExtra = !!extra && !(typeof extra === 'string' && extra.trim() === ''); + + const curExtra = hasExtra ? extra : null; + // ============================== Refs ============================== React.useImperativeHandle(ref, () => ({ ...panelRef.current, @@ -77,6 +82,7 @@ const Content = React.forwardRef((props, ref) => { >; @@ -55,4 +63,6 @@ export type IDialogPropTypes = { // Refs panelRef?: React.Ref; + + extra?: ReactNode; }; diff --git a/tests/__snapshots__/index.spec.tsx.snap b/tests/__snapshots__/index.spec.tsx.snap index d7886512..6b2cb58e 100644 --- a/tests/__snapshots__/index.spec.tsx.snap +++ b/tests/__snapshots__/index.spec.tsx.snap @@ -35,6 +35,9 @@ exports[`dialog add rootClassName and rootStyle should render correct 1`] = ` class="rc-dialog-close-x" /> +
diff --git a/tests/index.spec.tsx b/tests/index.spec.tsx index e6c075ea..954b5727 100644 --- a/tests/index.spec.tsx +++ b/tests/index.spec.tsx @@ -1,5 +1,5 @@ /* eslint-disable react/no-render-return-value, max-classes-per-file, func-names, no-console */ -import { fireEvent, render, act } from '@testing-library/react'; +import { fireEvent, render, act, screen } from '@testing-library/react'; import { Provider } from '@rc-component/motion'; import KeyCode from '@rc-component/util/lib/KeyCode'; import React, { cloneElement, useEffect } from 'react'; @@ -733,4 +733,40 @@ describe('dialog', () => { expect(document.querySelector('.rc-dialog')).toBeTruthy(); expect(document.querySelector('.rc-dialog-close')).toBeFalsy(); }); + + it('should render extra when extra is a React node', () => { + render(Node} />); + + expect(screen.getByTestId('extra-node')).toBeInTheDocument(); + }); + + it('does not render extra when extra is empty string', () => { + render(); + expect(screen.queryByTestId('.rc-dialog-extra')).toBeNull(); + }); + + it('does not render extra when extra is string with only spaces', () => { + render(); + expect(screen.queryByText(' ')).toBeNull(); + }); + + it('renders extra when extra is non-empty string', () => { + render(); + expect(screen.getByText('hello')).toBeInTheDocument(); + const extraDiv = document.querySelector('.rc-dialog-extra'); + expect(extraDiv).toHaveTextContent('hello'); + }); + + it('does not render extra when extra is null or undefined', () => { + const { container } = render(); + expect(container.querySelector('.rc-dialog-extra')).toBeNull(); + + const { container: container2 } = render(); + expect(container2.querySelector('.rc-dialog-extra')).toBeNull(); + }); + + it('renders extra when extra is a non-empty string', () => { + render(); + expect(screen.getByText('Extra Text')).toBeInTheDocument(); + }); });