feat: improve Semantic for Drawer (#52247)
Some checks are pending
Publish Any Commit / build (push) Waiting to run
✅ test v6 / lint (push) Waiting to run
✅ test v6 / test-react-legacy (18, 1/2) (push) Waiting to run
✅ test v6 / test-react-legacy (18, 2/2) (push) Waiting to run
✅ test v6 / test-node (push) Waiting to run
✅ test v6 / test-react-latest (dom, 1/2) (push) Waiting to run
✅ test v6 / test-react-latest (dom, 2/2) (push) Waiting to run
✅ test v6 / test-react-latest-dist (dist, 1/2) (push) Blocked by required conditions
✅ test v6 / test-react-latest-dist (dist, 2/2) (push) Blocked by required conditions
✅ test v6 / test-react-latest-dist (dist-min, 1/2) (push) Blocked by required conditions
✅ test v6 / test-react-latest-dist (dist-min, 2/2) (push) Blocked by required conditions
✅ test v6 / test-coverage (push) Blocked by required conditions
✅ test v6 / build (push) Waiting to run
✅ test v6 / test lib/es module (es, 1/2) (push) Waiting to run
✅ test v6 / test lib/es module (es, 2/2) (push) Waiting to run
✅ test v6 / test lib/es module (lib, 1/2) (push) Waiting to run
✅ test v6 / test lib/es module (lib, 2/2) (push) Waiting to run
👁️ Visual Regression Persist Start / test image (push) Waiting to run

* feat: improve Semantic for Drawer

* update content to section

* fix

* update snap

* sort
This commit is contained in:
thinkasany 2025-01-08 15:31:57 +08:00 committed by GitHub
parent 3c90842082
commit 2c3c5d169c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 198 additions and 85 deletions

View File

@ -14136,7 +14136,7 @@ exports[`ConfigProvider components Drawer configProvider 1`] = `
>
<div
aria-modal="true"
class="config-drawer-content"
class="config-drawer-section"
role="dialog"
>
<div
@ -14207,7 +14207,7 @@ exports[`ConfigProvider components Drawer configProvider componentDisabled 1`] =
>
<div
aria-modal="true"
class="config-drawer-content"
class="config-drawer-section"
role="dialog"
>
<div
@ -14278,7 +14278,7 @@ exports[`ConfigProvider components Drawer configProvider componentSize large 1`]
>
<div
aria-modal="true"
class="config-drawer-content"
class="config-drawer-section"
role="dialog"
>
<div
@ -14349,7 +14349,7 @@ exports[`ConfigProvider components Drawer configProvider componentSize middle 1`
>
<div
aria-modal="true"
class="config-drawer-content"
class="config-drawer-section"
role="dialog"
>
<div
@ -14420,7 +14420,7 @@ exports[`ConfigProvider components Drawer configProvider componentSize small 1`]
>
<div
aria-modal="true"
class="config-drawer-content"
class="config-drawer-section"
role="dialog"
>
<div
@ -14491,7 +14491,7 @@ exports[`ConfigProvider components Drawer normal 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -14562,7 +14562,7 @@ exports[`ConfigProvider components Drawer prefixCls 1`] = `
>
<div
aria-modal="true"
class="prefix-Drawer-content"
class="prefix-Drawer-section"
role="dialog"
>
<div

View File

@ -175,8 +175,8 @@ describe('ConfigProvider support style and className props', () => {
</ConfigProvider>,
);
const selectors = '.ant-drawer-content .ant-drawer-close .cp-test-close-icon';
expect(document.querySelector('.ant-drawer-content')).toHaveClass('test-class');
const selectors = '.ant-drawer-section .ant-drawer-close .cp-test-close-icon';
expect(document.querySelector('.ant-drawer-section')).toHaveClass('test-class');
expect(document.querySelector<HTMLSpanElement>(selectors)).toBeTruthy();
});
@ -194,7 +194,7 @@ describe('ConfigProvider support style and className props', () => {
</ConfigProvider>,
);
const selectors = '.ant-drawer-content .ant-drawer-close .cp-test-close-icon';
const selectors = '.ant-drawer-section .ant-drawer-close .cp-test-close-icon';
expect(document.querySelector<HTMLSpanElement>(selectors)).toBeTruthy();
expect(document.querySelector('*[aria-label="Close Btn"]')).toBeTruthy();
});
@ -210,7 +210,7 @@ describe('ConfigProvider support style and className props', () => {
</ConfigProvider>,
);
expect(document.querySelector('.ant-drawer-content')).toHaveStyle(
expect(document.querySelector('.ant-drawer-section')).toHaveStyle(
'color: red; font-size: 16px;',
);
});

View File

@ -7,17 +7,20 @@ import type { ClosableType } from '../_util/hooks/useClosable';
import { ConfigContext } from '../config-provider';
import Skeleton from '../skeleton';
export interface DrawerClassNames extends NonNullable<RCDrawerProps['classNames']> {
header?: string;
body?: string;
footer?: string;
}
export type SemanticName =
| 'root'
| 'mask'
| 'header'
| 'title'
| 'extra'
| 'section'
| 'body'
| 'footer'
| 'wrapper';
export interface DrawerStyles extends NonNullable<RCDrawerProps['styles']> {
header?: React.CSSProperties;
body?: React.CSSProperties;
footer?: React.CSSProperties;
}
export type DrawerClassNames = Partial<Record<SemanticName, string>>;
export type DrawerStyles = Partial<Record<SemanticName, React.CSSProperties>>;
export interface DrawerPanelProps {
prefixCls: string;
@ -112,9 +115,37 @@ const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
>
<div className={`${prefixCls}-header-title`}>
{mergedCloseIcon}
{title && <div className={`${prefixCls}-title`}>{title}</div>}
{title && (
<div
className={classNames(
`${prefixCls}-title`,
drawerContext?.classNames?.title,
drawerClassNames?.title,
)}
style={{
...drawerContext?.styles?.title,
...drawerStyles?.title,
}}
>
{title}
</div>
)}
</div>
{extra && <div className={`${prefixCls}-extra`}>{extra}</div>}
{extra && (
<div
className={classNames(
`${prefixCls}-extra`,
drawerContext?.classNames?.extra,
drawerClassNames?.extra,
)}
style={{
...drawerContext?.styles?.extra,
...drawerStyles?.extra,
}}
>
{extra}
</div>
)}
</div>
);
}, [mergedClosable, mergedCloseIcon, extra, headerStyle, prefixCls, title]);

View File

@ -38,7 +38,7 @@ describe('Drawer', () => {
fireEvent.animationEnd(mask);
}
const panel = document.querySelector('.ant-drawer-content');
const panel = document.querySelector('.ant-drawer-section');
if (panel) {
fireEvent.animationEnd(panel);
}
@ -349,7 +349,7 @@ describe('Drawer', () => {
header: getStyle1(),
body: getStyle1(),
footer: getStyle1(),
content: getStyle1(),
section: getStyle1(),
wrapper: getStyle1(),
mask: getStyle1(),
}}
@ -411,4 +411,73 @@ describe('Drawer', () => {
triggerMotion();
expect(container.querySelector('#test')).toBeTruthy();
});
it('should apply custom styles to Drawer', () => {
const customClassNames = {
root: 'custom-root',
mask: 'custom-mask',
header: 'custom-header',
title: 'custom-title',
extra: 'custom-extra',
section: 'custom-section',
body: 'custom-body',
footer: 'custom-footer',
};
const customStyles = {
root: { fontSize: '24px' },
mask: { backgroundColor: 'rgba(0, 0, 0, 0.5)' },
header: { borderBottom: '1px solid #e8e8e8' },
title: { fontWeight: 'bold' },
extra: { color: 'blue' },
section: { padding: '24px' },
body: { color: 'green' },
footer: { color: 'yellow' },
};
const { container } = render(
<Drawer
classNames={customClassNames}
styles={customStyles}
title="Title"
placement="right"
footer={<>Footer</>}
closable={false}
open
getContainer={false}
extra={<>Cancel</>}
>
<p>Some contents...</p>
</Drawer>,
);
const rootElement = container.querySelector('.ant-drawer') as HTMLElement;
const maskElement = container.querySelector('.ant-drawer-mask') as HTMLElement;
const headerElement = container.querySelector('.ant-drawer-header') as HTMLElement;
const titleElement = container.querySelector('.ant-drawer-title') as HTMLElement;
const extraElement = container.querySelector('.ant-drawer-extra') as HTMLElement;
const sectionElement = container.querySelector('.ant-drawer-section') as HTMLElement;
const bodyElement = container.querySelector('.ant-drawer-body') as HTMLElement;
const footerElement = container.querySelector('.ant-drawer-footer') as HTMLElement;
// check classNames
expect(rootElement.classList).toContain('custom-root');
expect(maskElement.classList).toContain('custom-mask');
expect(headerElement.classList).toContain('custom-header');
expect(titleElement.classList).toContain('custom-title');
expect(extraElement.classList).toContain('custom-extra');
expect(sectionElement.classList).toContain('custom-section');
expect(bodyElement.classList).toContain('custom-body');
expect(footerElement.classList).toContain('custom-footer');
// check styles
expect(rootElement.style.fontSize).toBe('24px');
expect(maskElement.style.backgroundColor).toBe('rgba(0, 0, 0, 0.5)');
expect(headerElement.style.borderBottom).toBe('1px solid #e8e8e8');
expect(titleElement.style.fontWeight).toBe('bold');
expect(extraElement.style.color).toBe('blue');
expect(sectionElement.style.padding).toBe('24px');
expect(bodyElement.style.color).toBe('green');
expect(footerElement.style.color).toBe('yellow');
});
});

View File

@ -76,14 +76,14 @@ describe('Drawer', () => {
act(() => {
jest.runAllTimers();
});
fireEvent.animationEnd(container.querySelector('.ant-drawer-content')!);
fireEvent.animationEnd(container.querySelector('.ant-drawer-section')!);
expect(container.querySelector('.ant-drawer')).toBeTruthy();
});
it('dom should be existed after close twice when getContainer is false', () => {
const { container, rerender } = render(<DrawerTest open getContainer={false} />);
expect(container.querySelector('.ant-drawer-content')).toBeTruthy();
expect(container.querySelector('.ant-drawer-section')).toBeTruthy();
// Hide
rerender(<DrawerTest open={false} getContainer={false} />);

View File

@ -20,7 +20,7 @@ exports[`Drawer Drawer loading have a spinner 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -111,7 +111,7 @@ exports[`Drawer className is test_drawer 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -184,7 +184,7 @@ exports[`Drawer closable is false 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -228,7 +228,7 @@ exports[`Drawer getContainer return undefined 2`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -302,7 +302,7 @@ exports[`Drawer have a footer 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -380,7 +380,7 @@ exports[`Drawer have a title 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -458,7 +458,7 @@ exports[`Drawer render correctly 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -531,7 +531,7 @@ exports[`Drawer render top drawer 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -608,7 +608,7 @@ exports[`Drawer style migrate match between styles and deprecated style prop 1`]
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
style="font-size: 13px;"
>
@ -695,7 +695,7 @@ exports[`Drawer style migrate match between styles and deprecated style prop 2`]
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
style="font-size: 13px;"
>
@ -781,7 +781,7 @@ exports[`Drawer style/drawerStyle/headerStyle/bodyStyle should work 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
style="background-color: rgb(0, 136, 204);"
>
@ -857,7 +857,7 @@ exports[`Drawer support closeIcon 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div

View File

@ -20,7 +20,7 @@ exports[`Drawer render correctly 1`] = `
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div

View File

@ -29,7 +29,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -147,7 +147,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content acss-1g5mw59"
class="ant-drawer-section acss-1g5mw59"
role="dialog"
style="box-shadow: -10px 0 10px #666;"
>
@ -239,7 +239,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content acss-1g5mw59"
class="ant-drawer-section acss-1g5mw59"
role="dialog"
style="box-shadow: -10px 0 10px #666;"
>
@ -412,7 +412,7 @@ exports[`renders components/drawer/demo/config-provider.tsx extend context corre
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -607,7 +607,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -763,7 +763,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -2838,7 +2838,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -2948,7 +2948,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -2995,7 +2995,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -3066,7 +3066,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -3261,7 +3261,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -3340,7 +3340,7 @@ exports[`renders components/drawer/demo/render-in-current.tsx extend context cor
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -3579,7 +3579,7 @@ exports[`renders components/drawer/demo/scroll-debug.tsx extend context correctl
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -3645,7 +3645,7 @@ exports[`renders components/drawer/demo/scroll-debug.tsx extend context correctl
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -3730,7 +3730,7 @@ exports[`renders components/drawer/demo/scroll-debug.tsx extend context correctl
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -3840,7 +3840,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div
@ -4070,7 +4070,7 @@ Array [
>
<div
aria-modal="true"
class="ant-drawer-content"
class="ant-drawer-section"
role="dialog"
>
<div

View File

@ -51,7 +51,7 @@ describe('Drawer.typescript', () => {
header: style,
body: style,
footer: style,
content: style,
section: style,
wrapper: style,
mask: style,
}}

View File

@ -1,23 +1,29 @@
import React from 'react';
import { Drawer, Typography } from 'antd';
import { Button, Drawer, Typography } from 'antd';
import SemanticPreview from '../../../.dumi/components/SemanticPreview';
import useLocale from '../../../.dumi/hooks/useLocale';
const locales = {
cn: {
root: '根元素',
mask: '遮罩层元素',
content: 'Drawer 容器元素',
section: 'Drawer 容器元素',
header: '头部元素',
body: '内容元素',
footer: '底部元素',
title: '标题元素',
extra: '额外元素',
},
en: {
root: 'Root element',
mask: 'Mask element',
content: 'Drawer container element',
section: 'Drawer container element',
header: 'Header element',
body: 'Body element',
footer: 'Footer element',
title: 'Title element',
extra: 'Extra element',
},
};
@ -26,9 +32,12 @@ const App: React.FC = () => {
return (
<SemanticPreview
semantics={[
{ name: 'root', desc: locale.root, version: '6.0.0' },
{ name: 'mask', desc: locale.mask, version: '5.13.0' },
{ name: 'content', desc: locale.content, version: '5.13.0' },
{ name: 'section', desc: locale.section, version: '6.0.0' },
{ name: 'header', desc: locale.header, version: '5.13.0' },
{ name: 'title', desc: locale.title, version: '6.0.0' },
{ name: 'extra', desc: locale.extra, version: '6.0.0' },
{ name: 'body', desc: locale.body, version: '5.13.0' },
{ name: 'footer', desc: locale.footer, version: '5.13.0' },
]}
@ -41,6 +50,7 @@ const App: React.FC = () => {
closable={false}
open
getContainer={false}
extra={<Button>Cancel</Button>}
>
<p>Some contents...</p>
</Drawer>

View File

@ -16,7 +16,7 @@ const useStyle = createStyles(({ token }) => ({
'my-drawer-footer': {
color: token.colorPrimary,
},
'my-drawer-content': {
'my-drawer-section': {
borderLeft: '2px dotted #333',
},
}));
@ -38,14 +38,14 @@ const App: React.FC = () => {
mask: styles['my-drawer-mask'],
header: styles['my-drawer-header'],
footer: styles['my-drawer-footer'],
content: styles['my-drawer-content'],
section: styles['my-drawer-section'],
};
const drawerStyles: DrawerStyles = {
mask: {
backdropFilter: 'blur(10px)',
},
content: {
section: {
boxShadow: '-10px 0 10px #666',
},
header: {

View File

@ -74,16 +74,6 @@ const Drawer: React.FC<DrawerProps> & {
? () => getPopupContainer(document.body)
: customizeGetContainer;
const drawerClassName = classNames(
{
'no-mask': !mask,
[`${prefixCls}-rtl`]: direction === 'rtl',
},
rootClassName,
hashId,
cssVarCls,
);
// ========================== Warning ===========================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning('Drawer');
@ -94,7 +84,7 @@ const Drawer: React.FC<DrawerProps> & {
['footerStyle', 'styles.footer'],
['contentWrapperStyle', 'styles.wrapper'],
['maskStyle', 'styles.mask'],
['drawerStyle', 'styles.content'],
['drawerStyle', 'styles.section'],
].forEach(([deprecatedName, newName]) => {
warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
});
@ -144,9 +134,21 @@ const Drawer: React.FC<DrawerProps> & {
const [zIndex, contextZIndex] = useZIndex('Drawer', rest.zIndex);
// =========================== Render ===========================
const { classNames: propClassNames = {}, styles: propStyles = {} } = rest;
const { classNames: propClassNames = {}, styles: propStyles = {}, rootStyle } = rest;
const { classNames: contextClassNames = {}, styles: contextStyles = {} } = drawer || {};
const drawerClassName = classNames(
{
'no-mask': !mask,
[`${prefixCls}-rtl`]: direction === 'rtl',
},
rootClassName,
hashId,
cssVarCls,
propClassNames?.root,
contextClassNames?.root,
);
return wrapCSSVar(
<ContextIsolator form space>
<zIndexContext.Provider value={contextZIndex}>
@ -158,7 +160,7 @@ const Drawer: React.FC<DrawerProps> & {
{...rest}
classNames={{
mask: classNames(propClassNames.mask, contextClassNames.mask),
content: classNames(propClassNames.content, contextClassNames.content),
section: classNames(propClassNames.section, contextClassNames.section),
wrapper: classNames(propClassNames.wrapper, contextClassNames.wrapper),
}}
styles={{
@ -167,10 +169,10 @@ const Drawer: React.FC<DrawerProps> & {
...maskStyle,
...contextStyles.mask,
},
content: {
...propStyles.content,
section: {
...propStyles.section,
...drawerStyle,
...contextStyles.content,
...contextStyles.section,
},
wrapper: {
...propStyles.wrapper,
@ -184,6 +186,7 @@ const Drawer: React.FC<DrawerProps> & {
width={mergedWidth}
height={mergedHeight}
style={{ ...drawer?.style, ...style }}
rootStyle={{ ...rootStyle, ...contextStyles?.root, ...propStyles?.root }}
className={classNames(drawer?.className, className)}
rootClassName={drawerClassName}
getContainer={getContainer}

View File

@ -140,7 +140,7 @@ const genDrawerStyle: GenerateStyle<DrawerToken> = (token) => {
boxShadow: token.boxShadowDrawerDown,
},
[`${componentCls}-content`]: {
[`${componentCls}-section`]: {
display: 'flex',
flexDirection: 'column',
width: '100%',

View File

@ -149,7 +149,7 @@ describe('Watermark', () => {
test(
'Drawer',
<Drawer open />,
() => document.body.querySelector('.ant-drawer-content')!.lastChild!,
() => document.body.querySelector('.ant-drawer-section')!.lastChild!,
);
it('inherit = false', async () => {
@ -160,7 +160,7 @@ describe('Watermark', () => {
);
await waitFakeTimer();
expect(document.body.querySelector('.ant-drawer-content')!.lastChild).toHaveClass(
expect(document.body.querySelector('.ant-drawer-section')!.lastChild).toHaveClass(
'ant-drawer-body',
);
});

View File

@ -123,7 +123,7 @@
"rc-checkbox": "~3.5.0",
"rc-collapse": "~3.9.0",
"rc-dialog": "~9.6.0",
"rc-drawer": "~7.2.0",
"rc-drawer": "~8.0.0",
"rc-dropdown": "~4.2.1",
"rc-field-form": "~2.7.0",
"rc-image": "~7.11.0",