mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 02:59:58 +08:00
feat: App support component (#45292)
* feat: App support component * test: update test case * chore: update ts
This commit is contained in:
parent
012e8781c5
commit
eaf4949ef0
@ -2,3 +2,5 @@
|
||||
export type LiteralUnion<T extends string> = T | (string & {});
|
||||
|
||||
export type AnyObject = Record<PropertyKey, any>;
|
||||
|
||||
export type CustomComponent<P = AnyObject> = React.ComponentType<P> | string;
|
||||
|
@ -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(
|
||||
<App component="section">
|
||||
<p />
|
||||
</App>,
|
||||
);
|
||||
|
||||
expect(container.querySelector('section.ant-app')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('to false', () => {
|
||||
const { container } = render(
|
||||
<App component={false}>
|
||||
<p />
|
||||
</App>,
|
||||
);
|
||||
|
||||
expect(container.querySelector('.ant-app')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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 |
|
||||
|
||||
|
@ -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<useAppProps>(AppContext);
|
||||
@ -29,6 +32,7 @@ const App: React.FC<AppProps> & { useApp: typeof useApp } = (props) => {
|
||||
message,
|
||||
notification,
|
||||
style,
|
||||
component = 'div',
|
||||
} = props;
|
||||
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
||||
const prefixCls = getPrefixCls('app', customizePrefixCls);
|
||||
@ -60,15 +64,22 @@ const App: React.FC<AppProps> & { useApp: typeof useApp } = (props) => {
|
||||
[messageApi, notificationApi, ModalApi],
|
||||
);
|
||||
|
||||
// ============================ Render ============================
|
||||
const Component = component === false ? React.Fragment : component;
|
||||
const rootProps = {
|
||||
className: customClassName,
|
||||
style,
|
||||
};
|
||||
|
||||
return wrapSSR(
|
||||
<AppContext.Provider value={memoizedContextValue}>
|
||||
<AppConfigContext.Provider value={mergedAppConfig}>
|
||||
<div className={customClassName} style={style}>
|
||||
<Component {...rootProps}>
|
||||
{ModalContextHolder}
|
||||
{messageContextHolder}
|
||||
{notificationContextHolder}
|
||||
{children}
|
||||
</div>
|
||||
</Component>
|
||||
</AppConfigContext.Provider>
|
||||
</AppContext.Provider>,
|
||||
);
|
||||
|
@ -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 |
|
||||
|
||||
|
@ -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<P = AnyObject> extends React.HTMLAttributes<HTMLElement> {
|
||||
@ -13,5 +13,5 @@ export interface FlexProps<P = AnyObject> extends React.HTMLAttributes<HTMLEleme
|
||||
flex?: React.CSSProperties['flex'];
|
||||
gap?: React.CSSProperties['gap'] | SizeType;
|
||||
children: React.ReactNode;
|
||||
component?: React.ComponentType<P> | string;
|
||||
component?: CustomComponent<P>;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user