mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 11:10:01 +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 LiteralUnion<T extends string> = T | (string & {});
|
||||||
|
|
||||||
export type AnyObject = Record<PropertyKey, any>;
|
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 React, { useEffect } from 'react';
|
||||||
|
import { SmileOutlined } from '@ant-design/icons';
|
||||||
import type { NotificationConfig } from 'antd/es/notification/interface';
|
import type { NotificationConfig } from 'antd/es/notification/interface';
|
||||||
|
|
||||||
import App from '..';
|
import App from '..';
|
||||||
import mountTest from '../../../tests/shared/mountTest';
|
import mountTest from '../../../tests/shared/mountTest';
|
||||||
import rtlTest from '../../../tests/shared/rtlTest';
|
import rtlTest from '../../../tests/shared/rtlTest';
|
||||||
@ -208,4 +209,26 @@ describe('App', () => {
|
|||||||
).toBeTruthy();
|
).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.
|
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
|
```tsx
|
||||||
import { App } from 'antd';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { App } from 'antd';
|
||||||
|
|
||||||
const MyPage: React.FC = () => {
|
const MyPage: React.FC = () => {
|
||||||
const { message, notification, modal } = App.useApp();
|
const { message, notification, modal } = App.useApp();
|
||||||
@ -102,8 +102,9 @@ export { message, modal, notification };
|
|||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
// sub page
|
// sub page
|
||||||
import { Button, Space } from 'antd';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Button, Space } from 'antd';
|
||||||
|
|
||||||
import { message } from './store';
|
import { message } from './store';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
@ -129,6 +130,7 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||||||
|
|
||||||
| Property | Description | Type | Default | Version |
|
| 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 |
|
| message | Global config for Message | [MessageConfig](/components/message/#messageconfig) | - | 5.3.0 |
|
||||||
| notification | Global config for Notification | [NotificationConfig](/components/notification/#notificationconfig) | - | 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 type { ReactNode } from 'react';
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import type { CustomComponent } from '../_util/type';
|
||||||
import type { ConfigConsumerProps } from '../config-provider';
|
import type { ConfigConsumerProps } from '../config-provider';
|
||||||
import { ConfigContext } from '../config-provider';
|
import { ConfigContext } from '../config-provider';
|
||||||
import useMessage from '../message/useMessage';
|
import useMessage from '../message/useMessage';
|
||||||
@ -16,6 +18,7 @@ export interface AppProps extends AppConfig {
|
|||||||
rootClassName?: string;
|
rootClassName?: string;
|
||||||
prefixCls?: string;
|
prefixCls?: string;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
|
component?: false | CustomComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useApp = () => React.useContext<useAppProps>(AppContext);
|
const useApp = () => React.useContext<useAppProps>(AppContext);
|
||||||
@ -29,6 +32,7 @@ const App: React.FC<AppProps> & { useApp: typeof useApp } = (props) => {
|
|||||||
message,
|
message,
|
||||||
notification,
|
notification,
|
||||||
style,
|
style,
|
||||||
|
component = 'div',
|
||||||
} = props;
|
} = props;
|
||||||
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
||||||
const prefixCls = getPrefixCls('app', customizePrefixCls);
|
const prefixCls = getPrefixCls('app', customizePrefixCls);
|
||||||
@ -60,15 +64,22 @@ const App: React.FC<AppProps> & { useApp: typeof useApp } = (props) => {
|
|||||||
[messageApi, notificationApi, ModalApi],
|
[messageApi, notificationApi, ModalApi],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ============================ Render ============================
|
||||||
|
const Component = component === false ? React.Fragment : component;
|
||||||
|
const rootProps = {
|
||||||
|
className: customClassName,
|
||||||
|
style,
|
||||||
|
};
|
||||||
|
|
||||||
return wrapSSR(
|
return wrapSSR(
|
||||||
<AppContext.Provider value={memoizedContextValue}>
|
<AppContext.Provider value={memoizedContextValue}>
|
||||||
<AppConfigContext.Provider value={mergedAppConfig}>
|
<AppConfigContext.Provider value={mergedAppConfig}>
|
||||||
<div className={customClassName} style={style}>
|
<Component {...rootProps}>
|
||||||
{ModalContextHolder}
|
{ModalContextHolder}
|
||||||
{messageContextHolder}
|
{messageContextHolder}
|
||||||
{notificationContextHolder}
|
{notificationContextHolder}
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</Component>
|
||||||
</AppConfigContext.Provider>
|
</AppConfigContext.Provider>
|
||||||
</AppContext.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 |
|
| message | App 内 Message 的全局配置 | [MessageConfig](/components/message-cn/#messageconfig) | - | 5.3.0 |
|
||||||
| notification | App 内 Notification 的全局配置 | [NotificationConfig](/components/notification-cn/#notificationconfig) | - | 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 React from 'react';
|
||||||
|
|
||||||
import type { AnyObject } from '../_util/type';
|
import type { AnyObject, CustomComponent } from '../_util/type';
|
||||||
import type { SizeType } from '../config-provider/SizeContext';
|
import type { SizeType } from '../config-provider/SizeContext';
|
||||||
|
|
||||||
export interface FlexProps<P = AnyObject> extends React.HTMLAttributes<HTMLElement> {
|
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'];
|
flex?: React.CSSProperties['flex'];
|
||||||
gap?: React.CSSProperties['gap'] | SizeType;
|
gap?: React.CSSProperties['gap'] | SizeType;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
component?: React.ComponentType<P> | string;
|
component?: CustomComponent<P>;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user