Skip to content

Commit bdb8573

Browse files
authored
feat: dialog support classNames (#365)
1 parent 8fb5644 commit bdb8573

File tree

7 files changed

+116
-6
lines changed

7 files changed

+116
-6
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ ReactDOM.render(
5353
| ---------------------- | ------------------------------ | --------- | ------------------------------------------------------------------------------- | ------- |
5454
| prefixCls | String | rc-dialog | The dialog dom node's prefixCls | |
5555
| className | String | | additional className for dialog | |
56+
| classNames | { mask?: string; wrapper?: string; header?: string; body?: string; footer?: string} | | pass className to target area | |
5657
| style | Object | {} | Root style for dialog element.Such as width, height | |
5758
| zIndex | Number | | | |
5859
| bodyStyle | Object | {} | body style for dialog body element.Such as height | |

src/Dialog/Content/Panel.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const Panel = React.forwardRef<ContentRef, PanelProps>((props, ref) => {
4242
forceRender,
4343
width,
4444
height,
45+
classNames: modalClassNames,
4546
} = props;
4647

4748
// ================================= Refs =================================
@@ -78,13 +79,13 @@ const Panel = React.forwardRef<ContentRef, PanelProps>((props, ref) => {
7879
// ================================ Render ================================
7980
let footerNode: React.ReactNode;
8081
if (footer) {
81-
footerNode = <div className={`${prefixCls}-footer`}>{footer}</div>;
82+
footerNode = <div className={classNames(`${prefixCls}-footer`, modalClassNames?.footer)}>{footer}</div>;
8283
}
8384

8485
let headerNode: React.ReactNode;
8586
if (title) {
8687
headerNode = (
87-
<div className={`${prefixCls}-header`}>
88+
<div className={classNames(`${prefixCls}-header`, modalClassNames?.header)}>
8889
<div className={`${prefixCls}-title`} id={ariaId}>
8990
{title}
9091
</div>
@@ -105,7 +106,7 @@ const Panel = React.forwardRef<ContentRef, PanelProps>((props, ref) => {
105106
<div className={`${prefixCls}-content`}>
106107
{closer}
107108
{headerNode}
108-
<div className={`${prefixCls}-body`} style={bodyStyle} {...bodyProps}>
109+
<div className={classNames(`${prefixCls}-body`, modalClassNames?.body)} style={bodyStyle} {...bodyProps}>
109110
{children}
110111
</div>
111112
{footerNode}

src/Dialog/Mask.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ export type MaskProps = {
88
motionName?: string;
99
style?: React.CSSProperties;
1010
maskProps?: React.HTMLAttributes<HTMLDivElement>;
11+
className?: string;
1112
};
1213

1314
export default function Mask(props: MaskProps) {
14-
const { prefixCls, style, visible, maskProps, motionName } = props;
15+
const { prefixCls, style, visible, maskProps, motionName, className } = props;
1516

1617
return (
1718
<CSSMotion
@@ -24,7 +25,7 @@ export default function Mask(props: MaskProps) {
2425
<div
2526
ref={ref}
2627
style={{ ...motionStyle, ...style }}
27-
className={classNames(`${prefixCls}-mask`, motionClassName)}
28+
className={classNames(`${prefixCls}-mask`, motionClassName, className)}
2829
{...maskProps}
2930
/>
3031
)}

src/Dialog/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export default function Dialog(props: IDialogPropTypes) {
4141
maskStyle,
4242
maskProps,
4343
rootClassName,
44+
classNames: modalClassNames,
4445
} = props;
4546

4647
const lastOutSideActiveElementRef = useRef<HTMLElement>();
@@ -169,11 +170,12 @@ export default function Dialog(props: IDialogPropTypes) {
169170
...maskStyle,
170171
}}
171172
maskProps={maskProps}
173+
className={modalClassNames?.mask}
172174
/>
173175
<div
174176
tabIndex={-1}
175177
onKeyDown={onWrapperKeyDown}
176-
className={classNames(`${prefixCls}-wrap`, wrapClassName)}
178+
className={classNames(`${prefixCls}-wrap`, wrapClassName, modalClassNames?.wrapper)}
177179
ref={wrapperRef}
178180
onClick={onWrapperClick}
179181
style={{ zIndex, ...wrapStyle, display: !animatedVisible ? 'none' : null }}

src/IDialogPropTypes.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import type { GetContainer } from 'rc-util/lib/PortalWrapper';
22
import type { CSSProperties, ReactNode, SyntheticEvent } from 'react';
33

4+
5+
export interface ModalClassNames {
6+
header: string;
7+
body: string;
8+
footer: string;
9+
mask: string;
10+
wrapper: string;
11+
}
12+
413
export type IDialogPropTypes = {
514
className?: string;
615
keyboard?: boolean;
@@ -35,6 +44,7 @@ export type IDialogPropTypes = {
3544
bodyProps?: any;
3645
maskProps?: any;
3746
rootClassName?: string;
47+
classNames?: ModalClassNames;
3848
wrapProps?: any;
3949
getContainer?: GetContainer | false;
4050
closeIcon?: ReactNode;

tests/__snapshots__/index.spec.tsx.snap

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,68 @@ exports[`dialog should render correct 1`] = `
106106
</div>
107107
</div>
108108
`;
109+
110+
exports[`dialog should support classNames 1`] = `
111+
<div
112+
class="rc-dialog-root"
113+
>
114+
<div
115+
class="rc-dialog-mask custom-mask"
116+
/>
117+
<div
118+
class="rc-dialog-wrap custom-wrapper"
119+
style="font-size: 10px;"
120+
tabindex="-1"
121+
>
122+
<div
123+
aria-labelledby="test-id"
124+
aria-modal="true"
125+
class="rc-dialog"
126+
role="dialog"
127+
style="width: 600px; height: 903px;"
128+
>
129+
<div
130+
aria-hidden="true"
131+
style="width: 0px; height: 0px; overflow: hidden; outline: none;"
132+
tabindex="0"
133+
/>
134+
<div
135+
class="rc-dialog-content"
136+
>
137+
<button
138+
aria-label="Close"
139+
class="rc-dialog-close"
140+
type="button"
141+
>
142+
<span
143+
class="rc-dialog-close-x"
144+
/>
145+
</button>
146+
<div
147+
class="rc-dialog-header custom-header"
148+
>
149+
<div
150+
class="rc-dialog-title"
151+
id="test-id"
152+
>
153+
Default
154+
</div>
155+
</div>
156+
<div
157+
class="rc-dialog-body custom-body"
158+
/>
159+
<div
160+
class="rc-dialog-footer custom-footer"
161+
>
162+
Footer
163+
</div>
164+
</div>
165+
<div
166+
aria-hidden="true"
167+
style="width: 0px; height: 0px; overflow: hidden; outline: none;"
168+
tabindex="0"
169+
/>
170+
</div>
171+
</div>
172+
</div>
173+
`;

tests/index.spec.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,4 +548,34 @@ describe('dialog', () => {
548548
expect(afterOpenChange).toHaveBeenCalledTimes(2);
549549
});
550550
});
551+
552+
it('should support classNames', () => {
553+
const wrapper = mount(
554+
<Dialog
555+
visible
556+
title='Default'
557+
footer='Footer'
558+
classNames={{
559+
header: 'custom-header',
560+
body: 'custom-body',
561+
footer: 'custom-footer',
562+
mask: 'custom-mask',
563+
wrapper: 'custom-wrapper',
564+
}}
565+
style={{ width: 600 }}
566+
height={903}
567+
wrapStyle={{ fontSize: 10 }}
568+
/>,
569+
);
570+
jest.runAllTimers();
571+
wrapper.update();
572+
573+
expect(wrapper.render()).toMatchSnapshot();
574+
console.log(wrapper.find('.rc-dialog-wrap').html())
575+
expect(wrapper.find('.rc-dialog-wrap').props().className).toContain('custom-wrapper');
576+
expect(wrapper.find('.rc-dialog-body').props().className).toContain('custom-body');
577+
expect(wrapper.find('.rc-dialog-header').props().className).toContain('custom-header');
578+
expect(wrapper.find('.rc-dialog-footer').props().className).toContain('custom-footer');
579+
expect(wrapper.find('.rc-dialog-mask').props().className).toContain('custom-mask');
580+
});
551581
});

0 commit comments

Comments
 (0)