diff --git a/components/_util/type.ts b/components/_util/type.ts index 02f9aaaca969..25115ca42007 100644 --- a/components/_util/type.ts +++ b/components/_util/type.ts @@ -2,3 +2,5 @@ export type LiteralUnion = T | (string & {}); export type AnyObject = Record; + +export type CustomComponent

= React.ComponentType

| string; diff --git a/components/app/__tests__/index.test.tsx b/components/app/__tests__/index.test.tsx index c67fed6ce686..7d2d5ebb1168 100644 --- a/components/app/__tests__/index.test.tsx +++ b/components/app/__tests__/index.test.tsx @@ -1,6 +1,7 @@ -import { SmileOutlined } from '@ant-design/icons'; import React, { useEffect } from 'react'; +import { SmileOutlined } from '@ant-design/icons'; import type { NotificationConfig } from 'antd/es/notification/interface'; + import App from '..'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; @@ -208,4 +209,26 @@ describe('App', () => { ).toBeTruthy(); }); }); + + describe('component', () => { + it('replace', () => { + const { container } = render( + +

+ , + ); + + expect(container.querySelector('section.ant-app')).toBeTruthy(); + }); + + it('to false', () => { + const { container } = render( + +

+ , + ); + + expect(container.querySelector('.ant-app')).toBeFalsy(); + }); + }); }); diff --git a/components/app/index.en-US.md b/components/app/index.en-US.md index 155e82a30649..ddbd04af366e 100644 --- a/components/app/index.en-US.md +++ b/components/app/index.en-US.md @@ -29,8 +29,8 @@ Application wrapper for some global usages. App provides upstream and downstream method calls through `Context`, because useApp needs to be used as a subcomponent, we recommend encapsulating App at the top level in the application. ```tsx -import { App } from 'antd'; import React from 'react'; +import { App } from 'antd'; const MyPage: React.FC = () => { const { message, notification, modal } = App.useApp(); @@ -102,8 +102,9 @@ export { message, modal, notification }; ```tsx // sub page -import { Button, Space } from 'antd'; import React from 'react'; +import { Button, Space } from 'antd'; + import { message } from './store'; export default () => { @@ -129,6 +130,7 @@ Common props ref:[Common props](/docs/react/common-props) | Property | Description | Type | Default | Version | | --- | --- | --- | --- | --- | +| component | Config render element, if `false` will not create DOM node | ComponentType | div | 5.11.0 | | message | Global config for Message | [MessageConfig](/components/message/#messageconfig) | - | 5.3.0 | | notification | Global config for Notification | [NotificationConfig](/components/notification/#notificationconfig) | - | 5.3.0 | diff --git a/components/app/index.tsx b/components/app/index.tsx index 56df12b953a8..cb1eb7a98f7d 100644 --- a/components/app/index.tsx +++ b/components/app/index.tsx @@ -1,6 +1,8 @@ -import classNames from 'classnames'; import type { ReactNode } from 'react'; import React, { useContext } from 'react'; +import classNames from 'classnames'; + +import type { CustomComponent } from '../_util/type'; import type { ConfigConsumerProps } from '../config-provider'; import { ConfigContext } from '../config-provider'; import useMessage from '../message/useMessage'; @@ -16,6 +18,7 @@ export interface AppProps extends AppConfig { rootClassName?: string; prefixCls?: string; children?: ReactNode; + component?: false | CustomComponent; } const useApp = () => React.useContext(AppContext); @@ -29,6 +32,7 @@ const App: React.FC & { useApp: typeof useApp } = (props) => { message, notification, style, + component = 'div', } = props; const { getPrefixCls } = useContext(ConfigContext); const prefixCls = getPrefixCls('app', customizePrefixCls); @@ -60,15 +64,22 @@ const App: React.FC & { useApp: typeof useApp } = (props) => { [messageApi, notificationApi, ModalApi], ); + // ============================ Render ============================ + const Component = component === false ? React.Fragment : component; + const rootProps = { + className: customClassName, + style, + }; + return wrapSSR( -

+ {ModalContextHolder} {messageContextHolder} {notificationContextHolder} {children} -
+ , ); diff --git a/components/app/index.zh-CN.md b/components/app/index.zh-CN.md index 7d6ee0c9704f..056c54716058 100644 --- a/components/app/index.zh-CN.md +++ b/components/app/index.zh-CN.md @@ -131,6 +131,7 @@ export default () => { | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | +| component | 设置渲染元素,为 `false` 则不创建 DOM 节点 | ComponentType | div | 5.11.0 | | message | App 内 Message 的全局配置 | [MessageConfig](/components/message-cn/#messageconfig) | - | 5.3.0 | | notification | App 内 Notification 的全局配置 | [NotificationConfig](/components/notification-cn/#notificationconfig) | - | 5.3.0 | diff --git a/components/flex/interface.ts b/components/flex/interface.ts index d5240cfcae05..6e7f42151b72 100644 --- a/components/flex/interface.ts +++ b/components/flex/interface.ts @@ -1,6 +1,6 @@ import type React from 'react'; -import type { AnyObject } from '../_util/type'; +import type { AnyObject, CustomComponent } from '../_util/type'; import type { SizeType } from '../config-provider/SizeContext'; export interface FlexProps

extends React.HTMLAttributes { @@ -13,5 +13,5 @@ export interface FlexProps

extends React.HTMLAttributes | string; + component?: CustomComponent

; }