From feffe70ebb72011ef311cb6e547b06b0ea139b99 Mon Sep 17 00:00:00 2001
From: tangjinzhou <415800467@qq.com>
Date: Fri, 5 May 2023 11:55:42 +0800
Subject: [PATCH] refactor: useNotification #6527
---
components/message/interface.ts | 2 +-
components/message/useMessage.tsx | 13 ++-
components/notification/PurePanel.tsx | 93 +++++++++-------
components/notification/index.tsx | 64 +----------
components/notification/interface.ts | 22 ++--
components/notification/useNotification.tsx | 102 +++++++++---------
components/vc-notification/Notification.tsx | 2 +-
.../vc-notification/useNotification.tsx | 44 ++++----
8 files changed, 148 insertions(+), 194 deletions(-)
diff --git a/components/message/interface.ts b/components/message/interface.ts
index 256e463ca..98d856e19 100644
--- a/components/message/interface.ts
+++ b/components/message/interface.ts
@@ -4,7 +4,7 @@ import type { Key, VueNode } from '../_util/type';
export type NoticeType = 'info' | 'success' | 'error' | 'warning' | 'loading';
export interface ConfigOptions {
- top?: number;
+ top?: number | string;
duration?: number;
prefixCls?: string;
getContainer?: () => HTMLElement;
diff --git a/components/message/useMessage.tsx b/components/message/useMessage.tsx
index 1f98d2df1..b81a07b3b 100644
--- a/components/message/useMessage.tsx
+++ b/components/message/useMessage.tsx
@@ -56,11 +56,14 @@ const Holder = defineComponent({
const [, hashId] = useStyle(prefixCls);
// =============================== Style ===============================
- const getStyles = () => ({
- left: '50%',
- transform: 'translateX(-50%)',
- top: `${top ?? DEFAULT_OFFSET}px`,
- });
+ const getStyles = () => {
+ const top = props.top ?? DEFAULT_OFFSET;
+ return {
+ left: '50%',
+ transform: 'translateX(-50%)',
+ top: typeof top === 'number' ? `${top}px` : top,
+ };
+ };
const getClassName = () => classNames(hashId.value, props.rtl ? `${prefixCls.value}-rtl` : '');
// ============================== Motion ===============================
diff --git a/components/notification/PurePanel.tsx b/components/notification/PurePanel.tsx
index c014509f3..c2a10a52a 100644
--- a/components/notification/PurePanel.tsx
+++ b/components/notification/PurePanel.tsx
@@ -1,4 +1,4 @@
-import { computed } from 'vue';
+import { computed, defineComponent } from 'vue';
import useStyle from './style';
import useConfigInject from '../config-provider/hooks/useConfigInject';
import type { IconType } from './interface';
@@ -6,13 +6,12 @@ import Notice from '../vc-notification/Notice';
import classNames from '../_util/classNames';
import type { NoticeProps } from '../vc-notification/Notice';
import type { VueNode } from '../_util/type';
-import {
- CheckCircleOutlined,
- CloseCircleOutlined,
- CloseOutlined,
- ExclamationCircleOutlined,
- InfoCircleOutlined,
-} from '@ant-design/icons-vue';
+import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
+import ExclamationCircleFilled from '@ant-design/icons-vue/ExclamationCircleFilled';
+import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
+import CheckCircleFilled from '@ant-design/icons-vue/CheckCircleFilled';
+import InfoCircleFilled from '@ant-design/icons-vue/InfoCircleFilled';
+import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
import { renderHelper } from '../_util/util';
export function getCloseIcon(prefixCls: string, closeIcon?: VueNode) {
@@ -34,11 +33,19 @@ export interface PureContentProps {
type?: IconType;
}
+export const TypeIcon = {
+ info: ,
+ success: ,
+ error: ,
+ warning: ,
+ loading: ,
+};
+
const typeToIcon = {
- success: CheckCircleOutlined,
- info: InfoCircleOutlined,
- error: CloseCircleOutlined,
- warning: ExclamationCircleOutlined,
+ success: CheckCircleFilled,
+ info: InfoCircleFilled,
+ error: CloseCircleFilled,
+ warning: ExclamationCircleFilled,
};
export function PureContent({
@@ -74,36 +81,42 @@ export function PureContent({
export interface PurePanelProps
extends Omit,
- Omit {
+ Omit {
prefixCls?: string;
}
/** @private Internal Component. Do not use in your production. */
-export default function PurePanel(props: PurePanelProps) {
- const { getPrefixCls } = useConfigInject('notification', props);
- const prefixCls = computed(() => props.prefixCls || getPrefixCls('notification'));
- const noticePrefixCls = `${prefixCls.value}-notice`;
+export default defineComponent({
+ name: 'PurePanel',
+ inheritAttrs: false,
+ props: ['prefixCls', 'icon', 'type', 'message', 'description', 'btn', 'closeIcon'] as any,
+ setup(props) {
+ const { getPrefixCls } = useConfigInject('notification', props);
+ const prefixCls = computed(() => props.prefixCls || getPrefixCls('notification'));
+ const noticePrefixCls = computed(() => `${prefixCls.value}-notice`);
- const [, hashId] = useStyle(prefixCls);
-
- return (
-
-
-
- );
-}
+ const [, hashId] = useStyle(prefixCls);
+ return () => {
+ return (
+
+
+
+ );
+ };
+ },
+});
diff --git a/components/notification/index.tsx b/components/notification/index.tsx
index 4179cc31e..3a639e15e 100644
--- a/components/notification/index.tsx
+++ b/components/notification/index.tsx
@@ -12,6 +12,7 @@ import type { NotificationInstance as VCNotificationInstance } from '../vc-notif
import classNames from '../_util/classNames';
import useStyle from './style';
import useNotification from './useNotification';
+import { getPlacementStyle } from './util';
export type NotificationPlacement =
| 'top'
@@ -77,63 +78,6 @@ function setNotificationConfig(options: ConfigProps) {
}
}
-function getPlacementStyle(
- placement: NotificationPlacement,
- top: string = defaultTop,
- bottom: string = defaultBottom,
-) {
- let style: CSSProperties;
- switch (placement) {
- case 'top':
- style = {
- left: '50%',
- transform: 'translateX(-50%)',
- right: 'auto',
- top,
- bottom: 'auto',
- };
- break;
- case 'topLeft':
- style = {
- left: '0px',
- top,
- bottom: 'auto',
- };
- break;
- case 'topRight':
- style = {
- right: '0px',
- top,
- bottom: 'auto',
- };
- break;
- case 'bottom':
- style = {
- left: '50%',
- transform: 'translateX(-50%)',
- right: 'auto',
- top: 'auto',
- bottom,
- };
- break;
- case 'bottomLeft':
- style = {
- left: '0px',
- top: 'auto',
- bottom,
- };
- break;
- default:
- style = {
- right: '0px',
- top: 'auto',
- bottom,
- };
- break;
- }
- return style;
-}
-
function getNotificationInstance(
{
prefixCls: customizePrefixCls,
@@ -167,7 +111,7 @@ function getNotificationInstance(
prefixCls: customizePrefixCls || defaultPrefixCls,
useStyle,
class: notificationClass,
- style: getPlacementStyle(placement, top, bottom),
+ style: getPlacementStyle(placement, top ?? defaultTop, bottom ?? defaultBottom),
appContext,
getContainer,
closeIcon: ({ prefixCls }) => {
@@ -210,8 +154,8 @@ export interface NotificationArgsProps {
class?: string;
readonly type?: IconType;
onClick?: () => void;
- top?: string;
- bottom?: string;
+ top?: string | number;
+ bottom?: string | number;
getContainer?: () => HTMLElement;
closeIcon?: VueNode | (() => VueNode);
appContext?: any;
diff --git a/components/notification/interface.ts b/components/notification/interface.ts
index a46d6245a..ddc291632 100644
--- a/components/notification/interface.ts
+++ b/components/notification/interface.ts
@@ -12,19 +12,19 @@ export type NotificationPlacement =
export type IconType = 'success' | 'info' | 'error' | 'warning';
export interface ArgsProps {
- message: VueNode;
- description?: VueNode;
- btn?: VueNode;
+ message: (() => VueNode) | VueNode;
+ description?: (() => VueNode) | VueNode;
+ btn?: (() => VueNode) | VueNode;
key?: Key;
onClose?: () => void;
duration?: number | null;
- icon?: VueNode;
+ icon?: (() => VueNode) | VueNode;
placement?: NotificationPlacement;
style?: CSSProperties;
- className?: string;
+ class?: string;
readonly type?: IconType;
onClick?: () => void;
- closeIcon?: VueNode;
+ closeIcon?: (() => VueNode) | VueNode;
}
type StaticFn = (args: ArgsProps) => void;
@@ -39,20 +39,20 @@ export interface NotificationInstance {
}
export interface GlobalConfigProps {
- top?: number;
- bottom?: number;
+ top?: number | string;
+ bottom?: number | string;
duration?: number;
prefixCls?: string;
getContainer?: () => HTMLElement;
placement?: NotificationPlacement;
- closeIcon?: VueNode;
+ closeIcon?: (() => VueNode) | VueNode;
rtl?: boolean;
maxCount?: number;
}
export interface NotificationConfig {
- top?: number;
- bottom?: number;
+ top?: number | string;
+ bottom?: number | string;
prefixCls?: string;
getContainer?: () => HTMLElement;
placement?: NotificationPlacement;
diff --git a/components/notification/useNotification.tsx b/components/notification/useNotification.tsx
index 52923a35a..9e3dc5533 100644
--- a/components/notification/useNotification.tsx
+++ b/components/notification/useNotification.tsx
@@ -84,68 +84,64 @@ export function useInternalNotification(
notificationConfig?: HolderProps,
): readonly [NotificationInstance, () => VNode] {
const holderRef = shallowRef(null);
-
+ const holderKey = Symbol('notificationHolderKey');
// ================================ API ================================
- const wrapAPI = computed(() => {
- // Wrap with notification content
+ // Wrap with notification content
- // >>> Open
- const open = (config: ArgsProps) => {
- if (!holderRef.value) {
- return;
- }
- const { open: originOpen, prefixCls, hashId } = holderRef.value;
- const noticePrefixCls = `${prefixCls}-notice`;
+ // >>> Open
+ const open = (config: ArgsProps) => {
+ if (!holderRef.value) {
+ return;
+ }
+ const { open: originOpen, prefixCls, hashId } = holderRef.value;
+ const noticePrefixCls = `${prefixCls}-notice`;
- const { message, description, icon, type, btn, className, ...restConfig } = config;
- return originOpen({
- placement: 'topRight',
- ...restConfig,
- content: (
-
- ),
- // @ts-ignore
- class: classNames(type && `${noticePrefixCls}-${type}`, hashId, className),
- });
- };
-
- // >>> destroy
- const destroy = (key?: Key) => {
- if (key !== undefined) {
- holderRef.value?.close(key);
- } else {
- holderRef.value?.destroy();
- }
- };
-
- const clone = {
- open,
- destroy,
- } as NotificationInstance;
-
- const keys = ['success', 'info', 'warning', 'error'] as const;
- keys.forEach(type => {
- clone[type] = config =>
- open({
- ...config,
- type,
- });
+ const { message, description, icon, type, btn, class: className, ...restConfig } = config;
+ return originOpen({
+ placement: 'topRight',
+ ...restConfig,
+ content: () => (
+
+ ),
+ // @ts-ignore
+ class: classNames(type && `${noticePrefixCls}-${type}`, hashId, className),
});
+ };
- return clone;
+ // >>> destroy
+ const destroy = (key?: Key) => {
+ if (key !== undefined) {
+ holderRef.value?.close(key);
+ } else {
+ holderRef.value?.destroy();
+ }
+ };
+
+ const wrapAPI = {
+ open,
+ destroy,
+ } as NotificationInstance;
+
+ const keys = ['success', 'info', 'warning', 'error'] as const;
+ keys.forEach(type => {
+ wrapAPI[type] = config =>
+ open({
+ ...config,
+ type,
+ });
});
// ============================== Return ===============================
return [
- wrapAPI.value,
- () => ,
+ wrapAPI,
+ () => ,
] as const;
}
diff --git a/components/vc-notification/Notification.tsx b/components/vc-notification/Notification.tsx
index 859c12b41..ff4bd02ff 100644
--- a/components/vc-notification/Notification.tsx
+++ b/components/vc-notification/Notification.tsx
@@ -29,7 +29,7 @@ export interface NoticeContent extends Omit VueNode) | VueNode;
onClose?: () => void;
style?: CSSProperties;
class?: String;
diff --git a/components/vc-notification/useNotification.tsx b/components/vc-notification/useNotification.tsx
index 77da44b64..c3fdc34ca 100644
--- a/components/vc-notification/useNotification.tsx
+++ b/components/vc-notification/useNotification.tsx
@@ -1,5 +1,5 @@
import type { CSSProperties } from 'vue';
-import { shallowRef, watch, ref, computed } from 'vue';
+import { shallowRef, watch, computed } from 'vue';
import HookNotification, { getUuid } from './HookNotification';
import type { NotificationInstance, OpenConfig, Placement } from './Notification';
import type { CSSMotionProps } from '../_util/transition';
@@ -82,7 +82,7 @@ export default function useNotification(rootConfig: NotificationConfig = {}) {
...shareConfig
} = rootConfig;
- const notices = ref([]);
+ const notices = shallowRef([]);
const notificationsRef = shallowRef();
const add = (originNotice: NoticeContent, holderCallback?: HolderReadyCallback) => {
const key = originNotice.key || getUuid();
@@ -132,29 +132,27 @@ export default function useNotification(rootConfig: NotificationConfig = {}) {
>
));
- const taskQueue = ref([] as Task[]);
+ const taskQueue = shallowRef([] as Task[]);
// ========================= Refs =========================
- const api = computed(() => {
- return {
- open: (config: OpenConfig) => {
- const mergedConfig = mergeConfig(shareConfig, config);
+ const api = {
+ open: (config: OpenConfig) => {
+ const mergedConfig = mergeConfig(shareConfig, config);
+ //@ts-ignore
+ if (mergedConfig.key === null || mergedConfig.key === undefined) {
//@ts-ignore
- if (mergedConfig.key === null || mergedConfig.key === undefined) {
- //@ts-ignore
- mergedConfig.key = `vc-notification-${uniqueKey}`;
- uniqueKey += 1;
- }
+ mergedConfig.key = `vc-notification-${uniqueKey}`;
+ uniqueKey += 1;
+ }
- taskQueue.value = [...taskQueue.value, { type: 'open', config: mergedConfig as any }];
- },
- close: key => {
- taskQueue.value = [...taskQueue.value, { type: 'close', key }];
- },
- destroy: () => {
- taskQueue.value = [...taskQueue.value, { type: 'destroy' }];
- },
- };
- });
+ taskQueue.value = [...taskQueue.value, { type: 'open', config: mergedConfig as any }];
+ },
+ close: key => {
+ taskQueue.value = [...taskQueue.value, { type: 'close', key }];
+ },
+ destroy: () => {
+ taskQueue.value = [...taskQueue.value, { type: 'destroy' }];
+ },
+ };
// ======================== Effect ========================
watch(taskQueue, () => {
@@ -180,5 +178,5 @@ export default function useNotification(rootConfig: NotificationConfig = {}) {
});
// ======================== Return ========================
- return [api.value, () => contextHolder.value] as const;
+ return [api, () => contextHolder.value] as const;
}