mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-11-29 18:48:32 +08:00
Merge remote-tracking branch 'origin/feat-v4'
This commit is contained in:
commit
12074a0dca
41
components/app/__tests__/__snapshots__/demo.test.js.snap
Normal file
41
components/app/__tests__/__snapshots__/demo.test.js.snap
Normal file
@ -0,0 +1,41 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/app/demo/basic.vue correctly 1`] = `
|
||||
<div class="ant-app">
|
||||
<!--teleport start-->
|
||||
<!--teleport end-->
|
||||
<!--teleport start-->
|
||||
<!--teleport end-->
|
||||
<div class="ant-space ant-space-horizontal ant-space-align-center">
|
||||
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open message</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open modal</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
<div class="ant-space-item"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open notification</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/app/demo/myPage.vue correctly 1`] = `
|
||||
<div class="ant-space ant-space-horizontal ant-space-align-center">
|
||||
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open message</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open modal</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
<div class="ant-space-item"><button class="ant-btn ant-btn-primary" type="button">
|
||||
<!----><span>Open notification</span>
|
||||
</button></div>
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
3
components/app/__tests__/demo.test.js
Normal file
3
components/app/__tests__/demo.test.js
Normal file
@ -0,0 +1,3 @@
|
||||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('app');
|
44
components/app/context.ts
Normal file
44
components/app/context.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { provide, inject, reactive } from 'vue';
|
||||
import type { InjectionKey } from 'vue';
|
||||
import type { MessageInstance, ConfigOptions as MessageConfig } from '../message/interface';
|
||||
import type { NotificationInstance, NotificationConfig } from '../notification/interface';
|
||||
import type { ModalStaticFunctions } from '../modal/confirm';
|
||||
|
||||
export type AppConfig = {
|
||||
message?: MessageConfig;
|
||||
notification?: NotificationConfig;
|
||||
};
|
||||
|
||||
export const AppConfigContextKey: InjectionKey<AppConfig> = Symbol('appConfigContext');
|
||||
|
||||
export const useProvideAppConfigContext = (appConfigContext: AppConfig) => {
|
||||
return provide(AppConfigContextKey, appConfigContext);
|
||||
};
|
||||
|
||||
export const useInjectAppConfigContext = () => {
|
||||
return inject(AppConfigContextKey, {});
|
||||
};
|
||||
|
||||
type ModalType = Omit<ModalStaticFunctions, 'warn'>;
|
||||
|
||||
export interface useAppProps {
|
||||
message: MessageInstance;
|
||||
notification: NotificationInstance;
|
||||
modal: ModalType;
|
||||
}
|
||||
|
||||
export const AppContextKey: InjectionKey<useAppProps> = Symbol('appContext');
|
||||
|
||||
export const useProvideAppContext = (appContext: useAppProps) => {
|
||||
return provide(AppContextKey, appContext);
|
||||
};
|
||||
|
||||
const defaultAppContext: useAppProps = reactive({
|
||||
message: {},
|
||||
notification: {},
|
||||
modal: {},
|
||||
} as useAppProps);
|
||||
|
||||
export const useInjectAppContext = () => {
|
||||
return inject(AppContextKey, defaultAppContext);
|
||||
};
|
26
components/app/demo/basic.vue
Normal file
26
components/app/demo/basic.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<docs>
|
||||
---
|
||||
order: 0
|
||||
title:
|
||||
zh-CN: 基本使用
|
||||
en-US: Basic Usage
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
获取 `message`、`notification`、`modal` 静态方法。
|
||||
|
||||
## en-US
|
||||
|
||||
Static method for `message`, `notification`, `modal`.
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-app>
|
||||
<my-page />
|
||||
</a-app>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import myPage from './myPage.vue';
|
||||
</script>
|
19
components/app/demo/index.vue
Normal file
19
components/app/demo/index.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<demo-sort :cols="1">
|
||||
<basic />
|
||||
</demo-sort>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import Basic from './basic.vue';
|
||||
import CN from '../index.zh-CN.md';
|
||||
import US from '../index.en-US.md';
|
||||
export default defineComponent({
|
||||
CN,
|
||||
US,
|
||||
components: {
|
||||
Basic,
|
||||
},
|
||||
});
|
||||
</script>
|
32
components/app/demo/myPage.vue
Normal file
32
components/app/demo/myPage.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="showMessage">Open message</a-button>
|
||||
<a-button type="primary" @click="showModal">Open modal</a-button>
|
||||
<a-button type="primary" @click="showNotification">Open notification</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { App } from 'ant-design-vue';
|
||||
|
||||
const { message, modal, notification } = App.useApp();
|
||||
|
||||
const showMessage = () => {
|
||||
message.success('Success!');
|
||||
};
|
||||
|
||||
const showModal = () => {
|
||||
modal.warning({
|
||||
title: 'This is a warning message',
|
||||
content: 'some messages...some messages...',
|
||||
});
|
||||
};
|
||||
|
||||
const showNotification = () => {
|
||||
notification.info({
|
||||
message: `Notification topLeft`,
|
||||
description: 'Hello, Ant Design Vue!!',
|
||||
placement: 'topLeft',
|
||||
});
|
||||
};
|
||||
</script>
|
129
components/app/index.en-US.md
Normal file
129
components/app/index.en-US.md
Normal file
@ -0,0 +1,129 @@
|
||||
---
|
||||
category: Components
|
||||
cols: 1
|
||||
type: Other
|
||||
title: App
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAAAAAAAAAAAADrJ8AQ/original
|
||||
---
|
||||
|
||||
Application wrapper for some global usages.
|
||||
|
||||
## When To Use
|
||||
|
||||
- Provide reset styles based on `.ant-app` element.
|
||||
- You could use static methods of `message/notification/Modal` form `useApp` without writing `contextHolder` manually.
|
||||
|
||||
## API
|
||||
|
||||
### App
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| message | Global config for Message | [MessageConfig](/components/message/#messageconfig) | - | 4.x |
|
||||
| notification | Global config for Notification | [NotificationConfig](/components/notification/#notificationconfig) | - | 4.x |
|
||||
|
||||
## How to use
|
||||
|
||||
### Basic usage
|
||||
|
||||
App provides upstream and downstream method calls through `provide/inject`, because useApp needs to be used as a subcomponent, we recommend encapsulating App at the top level in the application.
|
||||
|
||||
```html
|
||||
/*myPage.vue*/
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="showMessage">Open message</a-button>
|
||||
<a-button type="primary" @click="showModal">Open modal</a-button>
|
||||
<a-button type="primary" @click="showNotification">Open notification</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { App } from 'ant-design-vue';
|
||||
|
||||
const { message, modal, notification } = App.useApp();
|
||||
|
||||
const showMessage = () => {
|
||||
message.success('Success!');
|
||||
};
|
||||
|
||||
const showModal = () => {
|
||||
modal.warning({
|
||||
title: 'This is a warning message',
|
||||
content: 'some messages...some messages...',
|
||||
});
|
||||
};
|
||||
|
||||
const showNotification = () => {
|
||||
notification.info({
|
||||
message: `Notification topLeft`,
|
||||
description: 'Hello, Ant Design Vue!!',
|
||||
placement: 'topLeft',
|
||||
});
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
Note: App.useApp must be available under App.
|
||||
|
||||
#### Embedded usage scenarios (if not necessary, try not to do nesting)
|
||||
|
||||
```html
|
||||
<a-app>
|
||||
<a-space>
|
||||
...
|
||||
<a-app>...</a-app>
|
||||
</a-space>
|
||||
</a-app>
|
||||
```
|
||||
|
||||
#### Sequence with ConfigProvider
|
||||
|
||||
The App component can only use the token in the `ConfigProvider`, if you need to use the Token, the ConfigProvider and the App component must appear in pairs.
|
||||
|
||||
```html
|
||||
<a-config-provider theme="{{ ... }}">
|
||||
<a-app>...</a-app>
|
||||
</a-config-provider>
|
||||
```
|
||||
|
||||
#### Global scene (pinia scene)
|
||||
|
||||
```ts
|
||||
import { App } from 'ant-design-vue';
|
||||
import type { MessageInstance } from 'ant-design-vue/es/message/interface';
|
||||
import type { ModalStaticFunctions } from 'ant-design-vue/es/modal/confirm';
|
||||
import type { NotificationInstance } from 'ant-design-vue/es/notification/interface';
|
||||
|
||||
export const useGloablStore = defineStore('global', () => {
|
||||
const message: MessageInstance = ref();
|
||||
const notification: NotificationInstance = ref();
|
||||
const modal: Omit<ModalStaticFunctions, 'warn'> = ref();
|
||||
(() => {
|
||||
const staticFunction = App.useApp();
|
||||
message.value = staticFunction.message;
|
||||
modal.value = staticFunction.modal;
|
||||
notification.value = staticFunction.notification;
|
||||
})();
|
||||
|
||||
return { message, notification, modal };
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
// sub page
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="showMessage">Open message</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useGlobalStore } from '@/stores/global';
|
||||
const global = useGlobalStore();
|
||||
const showMessage = () => {
|
||||
global.message.success('Success!');
|
||||
};
|
||||
</script>
|
||||
```
|
83
components/app/index.tsx
Normal file
83
components/app/index.tsx
Normal file
@ -0,0 +1,83 @@
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import type { App as TypeApp, Plugin } from 'vue';
|
||||
import { initDefaultProps } from '../_util/props-util';
|
||||
import classNames from '../_util/classNames';
|
||||
import { objectType } from '../_util/type';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import useMessage from '../message/useMessage';
|
||||
import useModal from '../modal/useModal';
|
||||
import useNotification from '../notification/useNotification';
|
||||
import type { AppConfig } from './context';
|
||||
import {
|
||||
useProvideAppConfigContext,
|
||||
useInjectAppConfigContext,
|
||||
useProvideAppContext,
|
||||
useInjectAppContext,
|
||||
} from './context';
|
||||
import useStyle from './style';
|
||||
|
||||
export const AppProps = () => {
|
||||
return {
|
||||
rootClassName: String,
|
||||
message: objectType<AppConfig['message']>(),
|
||||
notification: objectType<AppConfig['notification']>(),
|
||||
};
|
||||
};
|
||||
|
||||
const useApp = () => {
|
||||
return useInjectAppContext();
|
||||
};
|
||||
|
||||
const App = defineComponent({
|
||||
name: 'AApp',
|
||||
props: initDefaultProps(AppProps(), {}),
|
||||
setup(props, { slots }) {
|
||||
const { prefixCls } = useConfigInject('app', props);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const customClassName = computed(() => {
|
||||
return classNames(hashId.value, prefixCls.value, props.rootClassName);
|
||||
});
|
||||
|
||||
const appConfig = useInjectAppConfigContext();
|
||||
const mergedAppConfig = computed(() => ({
|
||||
message: { ...appConfig.message, ...props.message },
|
||||
notification: { ...appConfig.notification, ...props.notification },
|
||||
}));
|
||||
useProvideAppConfigContext(mergedAppConfig.value);
|
||||
|
||||
const [messageApi, messageContextHolder] = useMessage(mergedAppConfig.value.message);
|
||||
const [notificationApi, notificationContextHolder] = useNotification(
|
||||
mergedAppConfig.value.notification,
|
||||
);
|
||||
const [ModalApi, ModalContextHolder] = useModal();
|
||||
|
||||
const memoizedContextValue = computed(() => ({
|
||||
message: messageApi,
|
||||
notification: notificationApi,
|
||||
modal: ModalApi,
|
||||
}));
|
||||
useProvideAppContext(memoizedContextValue.value);
|
||||
|
||||
return () => {
|
||||
return wrapSSR(
|
||||
<div class={customClassName.value}>
|
||||
{ModalContextHolder()}
|
||||
{messageContextHolder()}
|
||||
{notificationContextHolder()}
|
||||
{slots.default?.()}
|
||||
</div>,
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
App.useApp = useApp;
|
||||
|
||||
App.install = function (app: TypeApp) {
|
||||
app.component(App.name, App);
|
||||
};
|
||||
|
||||
export default App as typeof App &
|
||||
Plugin & {
|
||||
readonly useApp: typeof useApp;
|
||||
};
|
130
components/app/index.zh-CN.md
Normal file
130
components/app/index.zh-CN.md
Normal file
@ -0,0 +1,130 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 包裹组件
|
||||
cols: 1
|
||||
type: 其它
|
||||
title: App
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAAAAAAAAAAAADrJ8AQ/original
|
||||
---
|
||||
|
||||
新的包裹组件,提供重置样式和提供消费上下文的默认环境。
|
||||
|
||||
## 何时使用
|
||||
|
||||
- 提供可消费 provide/inject 的 `message.xxx`、`Modal.xxx`、`notification.xxx` 的静态方法,可以简化 useMessage 等方法需要手动植入 `contextHolder` 的问题。
|
||||
- 提供基于 `.ant-app` 的默认重置样式,解决原生元素没有 antd 规范样式的问题。
|
||||
|
||||
## API
|
||||
|
||||
### App
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| message | App 内 Message 的全局配置 | [MessageConfig](/components/message-cn/#messageconfig) | - | 4.x |
|
||||
| notification | App 内 Notification 的全局配置 | [NotificationConfig](/components/notification-cn/#notificationconfig) | - | 4.x |
|
||||
|
||||
## 如何使用
|
||||
|
||||
### 基础用法
|
||||
|
||||
App 组件通过 `provide/inject` 提供上下文方法调用,因而 useApp 需要作为子组件才能使用,我们推荐在应用中顶层包裹 App。
|
||||
|
||||
```html
|
||||
/*myPage.vue*/
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="showMessage">Open message</a-button>
|
||||
<a-button type="primary" @click="showModal">Open modal</a-button>
|
||||
<a-button type="primary" @click="showNotification">Open notification</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { App } from 'ant-design-vue';
|
||||
|
||||
const { message, modal, notification } = App.useApp();
|
||||
|
||||
const showMessage = () => {
|
||||
message.success('Success!');
|
||||
};
|
||||
|
||||
const showModal = () => {
|
||||
modal.warning({
|
||||
title: 'This is a warning message',
|
||||
content: 'some messages...some messages...',
|
||||
});
|
||||
};
|
||||
|
||||
const showNotification = () => {
|
||||
notification.info({
|
||||
message: `Notification topLeft`,
|
||||
description: 'Hello, Ant Design Vue!!',
|
||||
placement: 'topLeft',
|
||||
});
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
注意:App.useApp 必须在 App 之下方可使用。
|
||||
|
||||
#### 内嵌使用场景(如无必要,尽量不做嵌套)
|
||||
|
||||
```html
|
||||
<a-app>
|
||||
<a-space>
|
||||
...
|
||||
<a-app>...</a-app>
|
||||
</a-space>
|
||||
</a-app>
|
||||
```
|
||||
|
||||
#### 与 ConfigProvider 先后顺序
|
||||
|
||||
App 组件只能在 `ConfigProvider` 之下才能使用 Design Token, 如果需要使用其样式重置能力,则 ConfigProvider 与 App 组件必须成对出现。
|
||||
|
||||
```html
|
||||
<a-config-provider theme="{{ ... }}">
|
||||
<a-app>...</a-app>
|
||||
</a-config-provider>
|
||||
```
|
||||
|
||||
#### 全局场景 (pinia 场景)
|
||||
|
||||
```ts
|
||||
import { App } from 'ant-design-vue';
|
||||
import type { MessageInstance } from 'ant-design-vue/es/message/interface';
|
||||
import type { ModalStaticFunctions } from 'ant-design-vue/es/modal/confirm';
|
||||
import type { NotificationInstance } from 'ant-design-vue/es/notification/interface';
|
||||
|
||||
export const useGloablStore = defineStore('global', () => {
|
||||
const message: MessageInstance = ref();
|
||||
const notification: NotificationInstance = ref();
|
||||
const modal: Omit<ModalStaticFunctions, 'warn'> = ref();
|
||||
(() => {
|
||||
const staticFunction = App.useApp();
|
||||
message.value = staticFunction.message;
|
||||
modal.value = staticFunction.modal;
|
||||
notification.value = staticFunction.notification;
|
||||
})();
|
||||
|
||||
return { message, notification, modal };
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
// sub page
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="showMessage">Open message</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useGlobalStore } from '@/stores/global';
|
||||
const global = useGlobalStore();
|
||||
const showMessage = () => {
|
||||
global.message.success('Success!');
|
||||
};
|
||||
</script>
|
||||
```
|
22
components/app/style/index.ts
Normal file
22
components/app/style/index.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook } from '../../theme/internal';
|
||||
|
||||
export type ComponentToken = {};
|
||||
|
||||
interface AppToken extends FullToken<'App'> {}
|
||||
|
||||
// =============================== Base ===============================
|
||||
const genBaseStyle: GenerateStyle<AppToken> = token => {
|
||||
const { componentCls, colorText, fontSize, lineHeight, fontFamily } = token;
|
||||
return {
|
||||
[componentCls]: {
|
||||
color: colorText,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
fontFamily,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genComponentStyleHook('App', token => [genBaseStyle(token)]);
|
@ -261,3 +261,6 @@ export { default as QRCode } from './qrcode';
|
||||
|
||||
export type { TourProps, TourStepProps } from './tour';
|
||||
export { default as Tour } from './tour';
|
||||
|
||||
export type { AppProps } from './app';
|
||||
export { default as App } from './app';
|
||||
|
@ -46,7 +46,7 @@ import type { ComponentToken as TypographyComponentToken } from '../../typograph
|
||||
import type { ComponentToken as UploadComponentToken } from '../../upload/style';
|
||||
import type { ComponentToken as TourComponentToken } from '../../tour/style';
|
||||
import type { ComponentToken as QRCodeComponentToken } from '../../qrcode/style';
|
||||
// import type { ComponentToken as AppComponentToken } from '../../app/style';
|
||||
import type { ComponentToken as AppComponentToken } from '../../app/style';
|
||||
import type { ComponentToken as WaveToken } from '../../_util/wave/style';
|
||||
|
||||
export interface ComponentTokenMap {
|
||||
@ -112,7 +112,7 @@ export interface ComponentTokenMap {
|
||||
Progress?: ProgressComponentToken;
|
||||
Tour?: TourComponentToken;
|
||||
QRCode?: QRCodeComponentToken;
|
||||
// App?: AppComponentToken;
|
||||
App?: AppComponentToken;
|
||||
|
||||
// /** @private Internal TS definition. Do not use. */
|
||||
Wave?: WaveToken;
|
||||
|
Loading…
Reference in New Issue
Block a user