From f2608661a4784bff3dd5714aafe6e75b1ea7f4d0 Mon Sep 17 00:00:00 2001 From: RoxanneF Date: Mon, 26 May 2025 17:03:49 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0extra?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/index/Dialog.less | 18 +++++++++++++----- docs/examples/ant-design.tsx | 1 + src/Dialog/Content/Panel.tsx | 20 +++++++++++++++++++- src/Dialog/Content/index.tsx | 8 ++++++++ src/Dialog/index.tsx | 7 +++++++ src/IDialogPropTypes.tsx | 2 ++ tests/__snapshots__/index.spec.tsx.snap | 3 +++ 7 files changed, 53 insertions(+), 6 deletions(-) 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..b23c676f 100644 --- a/src/Dialog/Content/index.tsx +++ b/src/Dialog/Content/index.tsx @@ -30,12 +30,19 @@ 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 !== null && + extra !== undefined && + typeof extra !== 'boolean' && + !(typeof extra === 'string' && extra.trim() === ''); + // ============================== Refs ============================== React.useImperativeHandle(ref, () => ({ ...panelRef.current, @@ -77,6 +84,7 @@ const Content = React.forwardRef((props, ref) => { = (props) => { rootStyle, classNames: modalClassNames, styles: modalStyles, + extra, } = props; if (process.env.NODE_ENV !== 'production') { @@ -55,6 +56,12 @@ const Dialog: React.FC = (props) => { } } + const hasExtra = + extra !== null && + extra !== undefined && + typeof extra !== 'boolean' && + !(typeof extra === 'string' && extra.trim() === ''); + const lastOutSideActiveElementRef = useRef(null); const wrapperRef = useRef(null); const contentRef = useRef(null); diff --git a/src/IDialogPropTypes.tsx b/src/IDialogPropTypes.tsx index 8a5b305c..3bcc9761 100644 --- a/src/IDialogPropTypes.tsx +++ b/src/IDialogPropTypes.tsx @@ -55,4 +55,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" /> +
From c4eccd54a71a276395e46a0bcefe787873314832 Mon Sep 17 00:00:00 2001 From: RoxanneF Date: Mon, 26 May 2025 18:24:34 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0extra?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Dialog/Content/index.tsx | 8 ++++---- src/Dialog/index.tsx | 6 ------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/Dialog/Content/index.tsx b/src/Dialog/Content/index.tsx index b23c676f..f91d50ff 100644 --- a/src/Dialog/Content/index.tsx +++ b/src/Dialog/Content/index.tsx @@ -38,10 +38,10 @@ const Content = React.forwardRef((props, ref) => { const panelRef = useRef(null); const hasExtra = - extra !== null && - extra !== undefined && - typeof extra !== 'boolean' && - !(typeof extra === 'string' && extra.trim() === ''); + extra !== null && + extra !== undefined && + typeof extra !== 'boolean' && + !(typeof extra === 'string' && extra.trim() === ''); // ============================== Refs ============================== React.useImperativeHandle(ref, () => ({ diff --git a/src/Dialog/index.tsx b/src/Dialog/index.tsx index fcac4871..fd12b983 100644 --- a/src/Dialog/index.tsx +++ b/src/Dialog/index.tsx @@ -56,12 +56,6 @@ const Dialog: React.FC = (props) => { } } - const hasExtra = - extra !== null && - extra !== undefined && - typeof extra !== 'boolean' && - !(typeof extra === 'string' && extra.trim() === ''); - const lastOutSideActiveElementRef = useRef(null); const wrapperRef = useRef(null); const contentRef = useRef(null); From a303a442c278c1785a5f2cebb771363ba34ddda2 Mon Sep 17 00:00:00 2001 From: RoxanneF Date: Tue, 27 May 2025 09:44:56 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0extra?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Dialog/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Dialog/index.tsx b/src/Dialog/index.tsx index fd12b983..3512e772 100644 --- a/src/Dialog/index.tsx +++ b/src/Dialog/index.tsx @@ -43,7 +43,6 @@ const Dialog: React.FC = (props) => { rootStyle, classNames: modalClassNames, styles: modalStyles, - extra, } = props; if (process.env.NODE_ENV !== 'production') { From 5de510048708b416320386d20c549f9e6ae3d027 Mon Sep 17 00:00:00 2001 From: RoxanneF Date: Tue, 27 May 2025 20:45:51 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0extra?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/IDialogPropTypes.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/IDialogPropTypes.tsx b/src/IDialogPropTypes.tsx index 3bcc9761..bc81de04 100644 --- a/src/IDialogPropTypes.tsx +++ b/src/IDialogPropTypes.tsx @@ -1,7 +1,15 @@ import type { GetContainer } from '@rc-component/util/lib/PortalWrapper'; import type { CSSProperties, ReactNode, SyntheticEvent } from 'react'; -export type SemanticName = 'header' | 'body' | 'footer' | 'section' | 'title' | 'wrapper' | 'mask'; +export type SemanticName = + | 'header' + | 'body' + | 'footer' + | 'section' + | 'title' + | 'wrapper' + | 'mask' + | 'extra'; export type ModalClassNames = Partial>; From f9c344ed1b8b86acbfcbc1e7dbe123a5692ade04 Mon Sep 17 00:00:00 2001 From: RoxanneF Date: Wed, 28 May 2025 10:55:43 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0extra?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Dialog/Content/index.tsx | 10 ++++------ tests/index.spec.tsx | 38 +++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/Dialog/Content/index.tsx b/src/Dialog/Content/index.tsx index f91d50ff..b469f610 100644 --- a/src/Dialog/Content/index.tsx +++ b/src/Dialog/Content/index.tsx @@ -37,11 +37,9 @@ const Content = React.forwardRef((props, ref) => { const panelRef = useRef(null); - const hasExtra = - extra !== null && - extra !== undefined && - typeof extra !== 'boolean' && - !(typeof extra === 'string' && extra.trim() === ''); + const hasExtra = !!extra && !(typeof extra === 'string' && extra.trim() === ''); + + const curExtra = hasExtra ? extra : null; // ============================== Refs ============================== React.useImperativeHandle(ref, () => ({ @@ -84,7 +82,7 @@ const Content = React.forwardRef((props, ref) => { { 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(); + }); });