From f6760bff270db75bc428281a20afe9d8ca2c7809 Mon Sep 17 00:00:00 2001
From: tangjinzhou <415800467@qq.com>
Date: Wed, 29 Dec 2021 21:23:50 +0800
Subject: [PATCH 1/4] refactor: notification
---
components/notification/demo/custom-style.vue | 10 +-
components/notification/style/index.less | 48 +++-
.../style/{index.ts => index.tsx} | 0
components/notification/style/rtl.less | 53 ++++
components/vc-notification/Notice.jsx | 88 ------
components/vc-notification/Notice.tsx | 138 ++++++++++
components/vc-notification/Notification.jsx | 177 ------------
components/vc-notification/Notification.tsx | 251 ++++++++++++++++++
components/vc-notification/assets/index.less | 95 -------
.../vc-notification/{index.js => index.ts} | 3 +-
10 files changed, 488 insertions(+), 375 deletions(-)
rename components/notification/style/{index.ts => index.tsx} (100%)
create mode 100644 components/notification/style/rtl.less
delete mode 100644 components/vc-notification/Notice.jsx
create mode 100644 components/vc-notification/Notice.tsx
delete mode 100644 components/vc-notification/Notification.jsx
create mode 100644 components/vc-notification/Notification.tsx
delete mode 100644 components/vc-notification/assets/index.less
rename components/vc-notification/{index.js => index.ts} (67%)
diff --git a/components/notification/demo/custom-style.vue b/components/notification/demo/custom-style.vue
index 9fcac538b3..a053f7d75c 100644
--- a/components/notification/demo/custom-style.vue
+++ b/components/notification/demo/custom-style.vue
@@ -8,11 +8,11 @@ title:
## zh-CN
-使用 style 和 className 来定义样式。
+使用 `style` 和 `class` 来定义样式。
## en-US
-The style and className are available to customize Notification.
+The `style` and `class` are available to customize Notification.
@@ -33,6 +33,7 @@ export default defineComponent({
width: '600px',
marginLeft: `${335 - 600}px`,
},
+ class: 'notification-custom-class',
});
};
return {
@@ -41,3 +42,8 @@ export default defineComponent({
},
});
+
diff --git a/components/notification/style/index.less b/components/notification/style/index.less
index 04d7f24a4d..b85b73f55f 100644
--- a/components/notification/style/index.less
+++ b/components/notification/style/index.less
@@ -1,26 +1,25 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
+.popover-customize-bg(@notification-prefix-cls, @popover-background);
+
@notification-prefix-cls: ~'@{ant-prefix}-notification';
@notification-width: 384px;
-@notification-padding-vertical: 16px;
-@notification-padding-horizontal: 24px;
@notification-padding: @notification-padding-vertical @notification-padding-horizontal;
@notification-margin-bottom: 16px;
+@notification-margin-edge: 24px;
.@{notification-prefix-cls} {
.reset-component();
position: fixed;
z-index: @zindex-notification;
- width: @notification-width;
- max-width: ~'calc(100vw - 32px)';
- margin-right: 24px;
+ margin-right: @notification-margin-edge;
&-topLeft,
&-bottomLeft {
margin-right: 0;
- margin-left: 24px;
+ margin-left: @notification-margin-edge;
.@{notification-prefix-cls}-fade-enter.@{notification-prefix-cls}-fade-enter-active,
.@{notification-prefix-cls}-fade-appear.@{notification-prefix-cls}-fade-appear-active {
@@ -33,18 +32,31 @@
cursor: pointer;
}
+ &-hook-holder {
+ position: relative;
+ }
+
&-notice {
position: relative;
+ width: @notification-width;
+ max-width: ~'calc(100vw - @{notification-margin-edge} * 2)';
margin-bottom: @notification-margin-bottom;
+ margin-left: auto;
padding: @notification-padding;
overflow: hidden;
- line-height: 1.5;
+ line-height: @line-height-base;
+ word-wrap: break-word;
background: @notification-bg;
border-radius: @border-radius-base;
box-shadow: @shadow-2;
+ .@{notification-prefix-cls}-topLeft &,
+ .@{notification-prefix-cls}-bottomLeft & {
+ margin-right: auto;
+ margin-left: 0;
+ }
+
&-message {
- display: inline-block;
margin-bottom: 8px;
color: @heading-color;
font-size: @font-size-lg;
@@ -57,6 +69,7 @@
max-width: 4px;
background-color: transparent;
pointer-events: none;
+
&::before {
display: block;
content: '';
@@ -97,12 +110,15 @@
&-success {
color: @success-color;
}
+
&-info {
color: @info-color;
}
+
&-warning {
color: @warning-color;
}
+
&-error {
color: @error-color;
}
@@ -116,7 +132,12 @@
outline: none;
&:hover {
- color: shade(@text-color-secondary, 40%);
+ & when (@theme = dark) {
+ color: fade(@white, 85%);
+ }
+ & when not (@theme = dark) {
+ color: shade(@text-color-secondary, 40%);
+ }
}
}
@@ -134,9 +155,9 @@
&-fade-enter,
&-fade-appear {
- opacity: 0;
.notification-fade-effect();
+ opacity: 0;
animation-play-state: paused;
}
@@ -164,6 +185,7 @@
left: @notification-width;
opacity: 0;
}
+
100% {
left: 0;
opacity: 1;
@@ -175,6 +197,7 @@
right: @notification-width;
opacity: 0;
}
+
100% {
right: 0;
opacity: 1;
@@ -185,10 +208,9 @@
0% {
max-height: 150px;
margin-bottom: @notification-margin-bottom;
- padding-top: @notification-padding;
- padding-bottom: @notification-padding;
opacity: 1;
}
+
100% {
max-height: 0;
margin-bottom: 0;
@@ -197,3 +219,5 @@
opacity: 0;
}
}
+
+@import './rtl';
diff --git a/components/notification/style/index.ts b/components/notification/style/index.tsx
similarity index 100%
rename from components/notification/style/index.ts
rename to components/notification/style/index.tsx
diff --git a/components/notification/style/rtl.less b/components/notification/style/rtl.less
new file mode 100644
index 0000000000..9285a25cc5
--- /dev/null
+++ b/components/notification/style/rtl.less
@@ -0,0 +1,53 @@
+@import '../../style/themes/index';
+@import '../../style/mixins/index';
+
+@notification-prefix-cls: ~'@{ant-prefix}-notification';
+
+.@{notification-prefix-cls} {
+ &-rtl {
+ direction: rtl;
+ }
+
+ &-notice {
+ &-closable &-message {
+ .@{notification-prefix-cls}-rtl & {
+ padding-right: 0;
+ padding-left: 24px;
+ }
+ }
+
+ &-with-icon &-message {
+ .@{notification-prefix-cls}-rtl & {
+ margin-right: 48px;
+ margin-left: 0;
+ }
+ }
+
+ &-with-icon &-description {
+ .@{notification-prefix-cls}-rtl & {
+ margin-right: 48px;
+ margin-left: 0;
+ }
+ }
+
+ &-icon {
+ .@{notification-prefix-cls}-rtl & {
+ margin-right: 4px;
+ margin-left: 0;
+ }
+ }
+
+ &-close {
+ .@{notification-prefix-cls}-rtl & {
+ right: auto;
+ left: 22px;
+ }
+ }
+
+ &-btn {
+ .@{notification-prefix-cls}-rtl & {
+ float: left;
+ }
+ }
+ }
+}
diff --git a/components/vc-notification/Notice.jsx b/components/vc-notification/Notice.jsx
deleted file mode 100644
index 0a6f2346c8..0000000000
--- a/components/vc-notification/Notice.jsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import PropTypes from '../_util/vue-types';
-import { getComponent, getSlot } from '../_util/props-util';
-import BaseMixin from '../_util/BaseMixin';
-
-export default {
- mixins: [BaseMixin],
- props: {
- duration: PropTypes.number.def(1.5),
- closable: PropTypes.looseBool,
- prefixCls: PropTypes.string,
- update: PropTypes.looseBool,
- closeIcon: PropTypes.any,
- onClose: PropTypes.func,
- },
- watch: {
- duration() {
- this.restartCloseTimer();
- },
- },
-
- mounted() {
- this.startCloseTimer();
- },
- updated() {
- if (this.update) {
- this.restartCloseTimer();
- }
- },
-
- beforeUnmount() {
- this.clearCloseTimer();
- this.willDestroy = true; // beforeUnmount调用后依然会触发onMouseleave事件
- },
- methods: {
- close(e) {
- if (e) {
- e.stopPropagation();
- }
- this.clearCloseTimer();
- this.__emit('close');
- },
-
- startCloseTimer() {
- this.clearCloseTimer();
- if (!this.willDestroy && this.duration) {
- this.closeTimer = setTimeout(() => {
- this.close();
- }, this.duration * 1000);
- }
- },
-
- clearCloseTimer() {
- if (this.closeTimer) {
- clearTimeout(this.closeTimer);
- this.closeTimer = null;
- }
- },
- restartCloseTimer() {
- this.clearCloseTimer();
- this.startCloseTimer();
- },
- },
-
- render() {
- const { prefixCls, closable, clearCloseTimer, startCloseTimer, close, $attrs } = this;
- const componentClass = `${prefixCls}-notice`;
- const className = {
- [`${componentClass}`]: 1,
- [`${componentClass}-closable`]: closable,
- };
- const closeIcon = getComponent(this, 'closeIcon');
- return (
-
- );
- },
-};
diff --git a/components/vc-notification/Notice.tsx b/components/vc-notification/Notice.tsx
new file mode 100644
index 0000000000..e29039a88b
--- /dev/null
+++ b/components/vc-notification/Notice.tsx
@@ -0,0 +1,138 @@
+import type { Key } from '../_util/type';
+import { Teleport, computed, defineComponent, onMounted, watch, onUnmounted } from 'vue';
+import type { HTMLAttributes } from 'vue';
+import type { MouseEventHandler } from '../_util/EventInterface';
+import classNames from '../_util/classNames';
+
+interface DivProps extends HTMLAttributes {
+ // Ideally we would allow all data-* props but this would depend on https://github.com/microsoft/TypeScript/issues/28960
+ 'data-testid'?: string;
+}
+
+export interface NoticeProps {
+ prefixCls: string;
+ duration?: number | null;
+ updateMark?: string;
+ /** Mark as final key since set maxCount may keep the key but user pass key is different */
+ noticeKey: Key;
+ closeIcon?: any;
+ closable?: boolean;
+ props?: DivProps;
+ onClick?: MouseEventHandler;
+ onClose?: (key: Key) => void;
+
+ /** @private Only for internal usage. We don't promise that we will refactor this */
+ holder?: HTMLDivElement;
+
+ /** @private Provided by CSSMotionList */
+ visible?: boolean;
+}
+
+export default defineComponent({
+ name: 'Notice',
+ inheritAttrs: false,
+ props: [
+ 'prefixCls',
+ 'duration',
+ 'updateMark',
+ 'noticeKey',
+ 'closeIcon',
+ 'closable',
+ 'props',
+ 'onClick',
+ 'onClose',
+ 'holder',
+ 'visible',
+ ] as any,
+ setup(props, { attrs, slots }) {
+ let closeTimer: any;
+ const duration = computed(() => (props.duration === undefined ? 1.5 : props.duration));
+ const startCloseTimer = () => {
+ if (duration.value) {
+ closeTimer = setTimeout(() => {
+ close();
+ }, duration.value * 1000);
+ }
+ };
+
+ const clearCloseTimer = () => {
+ if (closeTimer) {
+ clearTimeout(closeTimer);
+ closeTimer = null;
+ }
+ };
+ const close = (e?: MouseEvent) => {
+ if (e) {
+ e.stopPropagation();
+ }
+ clearCloseTimer();
+ const { onClose, noticeKey } = props;
+ if (onClose) {
+ onClose(noticeKey);
+ }
+ };
+ const restartCloseTimer = () => {
+ clearCloseTimer();
+ startCloseTimer();
+ };
+ onMounted(() => {
+ startCloseTimer();
+ });
+ onUnmounted(() => {
+ clearCloseTimer();
+ });
+
+ watch(
+ [duration, () => props.updateMark, () => props.visible],
+ ([preDuration, preUpdateMark, preVisible], [newDuration, newUpdateMark, newVisible]) => {
+ if (
+ preDuration !== newDuration ||
+ preUpdateMark !== newUpdateMark ||
+ (preVisible !== newVisible && newVisible)
+ ) {
+ restartCloseTimer();
+ }
+ },
+ { flush: 'post' },
+ );
+ return () => {
+ const { prefixCls, closable, closeIcon = slots.closeIcon?.(), onClick, holder } = props;
+ const { class: className, style } = attrs;
+ const componentClass = `${prefixCls}-notice`;
+ const dataOrAriaAttributeProps = Object.keys(attrs).reduce(
+ (acc: Record, key: string) => {
+ if (key.substr(0, 5) === 'data-' || key.substr(0, 5) === 'aria-' || key === 'role') {
+ acc[key] = (attrs as any)[key];
+ }
+ return acc;
+ },
+ {},
+ );
+ const node = (
+
+ );
+
+ if (holder) {
+ return node }}>;
+ }
+
+ return node;
+ };
+ },
+});
diff --git a/components/vc-notification/Notification.jsx b/components/vc-notification/Notification.jsx
deleted file mode 100644
index 374ec9cc71..0000000000
--- a/components/vc-notification/Notification.jsx
+++ /dev/null
@@ -1,177 +0,0 @@
-import { defineComponent, createVNode, render as vueRender, onMounted, ref } from 'vue';
-import PropTypes from '../_util/vue-types';
-import { getComponent } from '../_util/props-util';
-import BaseMixin from '../_util/BaseMixin';
-import createChainedFunction from '../_util/createChainedFunction';
-import Notice from './Notice';
-import { getTransitionGroupProps, TransitionGroup } from '../_util/transition';
-import ConfigProvider, { globalConfigForApi } from '../config-provider';
-
-function noop() {}
-
-let seed = 0;
-const now = Date.now();
-
-function getUuid() {
- return `rcNotification_${now}_${seed++}`;
-}
-
-const Notification = defineComponent({
- mixins: [BaseMixin],
- props: {
- prefixCls: PropTypes.string.def('rc-notification'),
- transitionName: PropTypes.string,
- animation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).def('fade'),
- maxCount: PropTypes.number,
- closeIcon: PropTypes.any,
- },
- data() {
- return {
- notices: [],
- };
- },
- methods: {
- getTransitionName() {
- const props = this.$props;
- let transitionName = props.transitionName;
- if (!transitionName && props.animation) {
- transitionName = `${props.prefixCls}-${props.animation}`;
- }
- return transitionName;
- },
-
- add(notice) {
- const key = (notice.key = notice.key || getUuid());
- const { maxCount } = this.$props;
- this.setState(previousState => {
- const notices = previousState.notices;
- const noticeIndex = notices.map(v => v.key).indexOf(key);
- const updatedNotices = notices.concat();
- if (noticeIndex !== -1) {
- updatedNotices.splice(noticeIndex, 1, notice);
- } else {
- if (maxCount && notices.length >= maxCount) {
- // XXX, use key of first item to update new added (let React to move exsiting
- // instead of remove and mount). Same key was used before for both a) external
- // manual control and b) internal react 'key' prop , which is not that good.
- notice.updateKey = updatedNotices[0].updateKey || updatedNotices[0].key;
- updatedNotices.shift();
- }
- updatedNotices.push(notice);
- }
- return {
- notices: updatedNotices,
- };
- });
- },
-
- remove(key) {
- this.setState(previousState => {
- return {
- notices: previousState.notices.filter(notice => notice.key !== key),
- };
- });
- },
- },
-
- render() {
- const { prefixCls, notices, remove, getTransitionName, $attrs } = this;
- const transitionProps = getTransitionGroupProps(getTransitionName());
- const noticeNodes = notices.map((notice, index) => {
- const update = Boolean(index === notices.length - 1 && notice.updateKey);
- const key = notice.updateKey ? notice.updateKey : notice.key;
-
- const { content, duration, closable, onClose, style, class: className } = notice;
- const close = createChainedFunction(remove.bind(this, notice.key), onClose);
- const noticeProps = {
- prefixCls,
- duration,
- closable,
- update,
- closeIcon: getComponent(this, 'closeIcon', { prefixCls }),
- onClose: close,
- onClick: notice.onClick || noop,
- style,
- class: className,
- key,
- };
- return (
-
- {typeof content === 'function' ? content({ prefixCls }) : content}
-
- );
- });
- const className = {
- [prefixCls]: 1,
- };
- return (
-
-
- {noticeNodes}
-
-
- );
- },
-});
-
-Notification.newInstance = function newNotificationInstance(properties, callback) {
- const {
- name = 'notification',
- getContainer,
- appContext,
- prefixCls: customizePrefixCls,
- rootPrefixCls: customRootPrefixCls,
- ...props
- } = properties || {};
- const div = document.createElement('div');
- if (getContainer) {
- const root = getContainer();
- root.appendChild(div);
- } else {
- document.body.appendChild(div);
- }
- const Wrapper = defineComponent({
- setup(_props, { attrs }) {
- const notiRef = ref();
- onMounted(() => {
- callback({
- notice(noticeProps) {
- notiRef.value?.add(noticeProps);
- },
- removeNotice(key) {
- notiRef.value?.remove(key);
- },
- destroy() {
- vueRender(null, div);
- if (div.parentNode) {
- div.parentNode.removeChild(div);
- }
- },
- });
- });
- return () => {
- const global = globalConfigForApi;
- const prefixCls = global.getPrefixCls(name, customizePrefixCls);
- const rootPrefixCls = global.getRootPrefixCls(customRootPrefixCls, prefixCls);
- return (
-
-
-
- );
- };
- },
- });
-
- const vm = createVNode(Wrapper, props);
- vm.appContext = appContext || vm.appContext;
- vueRender(vm, div);
-};
-export default Notification;
diff --git a/components/vc-notification/Notification.tsx b/components/vc-notification/Notification.tsx
new file mode 100644
index 0000000000..77f06022a3
--- /dev/null
+++ b/components/vc-notification/Notification.tsx
@@ -0,0 +1,251 @@
+import { getTransitionGroupProps } from 'ant-design-vue/es/_util/transition';
+import type { Key } from 'ant-design-vue/es/_util/type';
+import type { CSSProperties } from 'vue';
+import {
+ createVNode,
+ computed,
+ defineComponent,
+ ref,
+ TransitionGroup,
+ onMounted,
+ render as vueRender,
+} from 'vue';
+import type { NoticeProps } from './Notice';
+import Notice from './Notice';
+import ConfigProvider, { globalConfigForApi } from '../config-provider';
+
+let seed = 0;
+const now = Date.now();
+
+function getUuid() {
+ const id = seed;
+ seed += 1;
+ return `rcNotification_${now}_${id}`;
+}
+
+export interface NoticeContent extends Omit {
+ prefixCls?: string;
+ key?: Key;
+ updateMark?: string;
+ content?: any;
+ onClose?: () => void;
+ style?: CSSProperties;
+ class?: String;
+}
+
+export type NoticeFunc = (noticeProps: NoticeContent) => void;
+export type HolderReadyCallback = (
+ div: HTMLDivElement,
+ noticeProps: NoticeProps & { key: Key },
+) => void;
+
+export interface NotificationInstance {
+ notice: NoticeFunc;
+ removeNotice: (key: Key) => void;
+ destroy: () => void;
+ component: Notification;
+
+ useNotification: () => [NoticeFunc, any];
+}
+
+export interface NotificationProps {
+ prefixCls?: string;
+ transitionName?: string;
+ animation?: string | object;
+ maxCount?: number;
+ closeIcon?: any;
+}
+
+type NotificationState = {
+ notice: NoticeContent & {
+ userPassKey?: Key;
+ };
+ holderCallback?: HolderReadyCallback;
+}[];
+
+const Notification = defineComponent({
+ name: 'Notification',
+ props: ['prefixCls', 'transitionName', 'animation', 'maxCount', 'closeIcon'] as any,
+ setup(props, { attrs, expose, slots }) {
+ const hookRefs = new Map();
+ const notices = ref([]);
+ const transitionProps = computed(() => {
+ const { prefixCls, animation = 'fade' } = props;
+ let name = props.transitionName;
+ if (!name && animation) {
+ name = `${prefixCls}-${animation}`;
+ }
+ return getTransitionGroupProps(name);
+ });
+
+ const add = (originNotice: NoticeContent, holderCallback?: HolderReadyCallback) => {
+ const key = originNotice.key || getUuid();
+ const notice: NoticeContent & { key: Key; userPassKey?: Key } = {
+ ...originNotice,
+ key,
+ };
+ const { maxCount } = props;
+ const noticeIndex = notices.value.map(v => v.notice.key).indexOf(key);
+ const updatedNotices = notices.value.concat();
+ if (noticeIndex !== -1) {
+ updatedNotices.splice(noticeIndex, 1, { notice, holderCallback } as any);
+ } else {
+ if (maxCount && notices.value.length >= maxCount) {
+ // XXX, use key of first item to update new added (let React to move exsiting
+ // instead of remove and mount). Same key was used before for both a) external
+ // manual control and b) internal react 'key' prop , which is not that good.
+ // eslint-disable-next-line no-param-reassign
+
+ // zombieJ: Not know why use `updateKey`. This makes Notice infinite loop in jest.
+ // Change to `updateMark` for compare instead.
+ // https://github.com/react-component/notification/commit/32299e6be396f94040bfa82517eea940db947ece
+ notice.key = updatedNotices[0].notice.key as Key;
+ notice.updateMark = getUuid();
+
+ // zombieJ: That's why. User may close by key directly.
+ // We need record this but not re-render to avoid upper issue
+ // https://github.com/react-component/notification/issues/129
+ notice.userPassKey = key;
+
+ updatedNotices.shift();
+ }
+ updatedNotices.push({ notice, holderCallback } as any);
+ }
+ notices.value = updatedNotices;
+ };
+
+ const remove = (removeKey: Key) => {
+ notices.value = notices.value.filter(({ notice: { key, userPassKey } }) => {
+ const mergedKey = userPassKey || key;
+ return mergedKey !== removeKey;
+ });
+ };
+ expose({
+ add,
+ remove,
+ });
+ return () => {
+ const { prefixCls, closeIcon = slots.closeIcon?.() } = props;
+ const noticeNodes = notices.value.map(({ notice, holderCallback }, index) => {
+ const updateMark = index === notices.value.length - 1 ? notice.updateMark : undefined;
+ const { key, userPassKey } = notice;
+
+ const { content } = notice;
+ const noticeProps = {
+ prefixCls,
+ closeIcon: typeof closeIcon === 'function' ? closeIcon({ prefixCls }) : closeIcon,
+ ...(notice as any),
+ ...notice.props,
+ key,
+ noticeKey: userPassKey || key,
+ updateMark,
+ onClose: (noticeKey: Key) => {
+ remove(noticeKey);
+ notice.onClose?.();
+ },
+ onClick: notice.onClick,
+ };
+ if (holderCallback) {
+ return (
+ {
+ if (typeof key === 'undefined') {
+ return;
+ }
+
+ if (div) {
+ hookRefs.set(key, div);
+ holderCallback(div, noticeProps);
+ } else {
+ hookRefs.delete(key);
+ }
+ }}
+ />
+ );
+ }
+ return (
+
+ {typeof content === 'function' ? content({ prefixCls }) : content}
+
+ );
+ });
+ const className = {
+ [prefixCls]: 1,
+ [attrs.class as string]: !!attrs.class,
+ };
+ return (
+
+
+ {noticeNodes}
+
+
+ );
+ };
+ },
+});
+
+Notification.newInstance = function newNotificationInstance(properties, callback) {
+ const {
+ name = 'notification',
+ getContainer,
+ appContext,
+ prefixCls: customizePrefixCls,
+ rootPrefixCls: customRootPrefixCls,
+ ...props
+ } = properties || {};
+ const div = document.createElement('div');
+ if (getContainer) {
+ const root = getContainer();
+ root.appendChild(div);
+ } else {
+ document.body.appendChild(div);
+ }
+ const Wrapper = defineComponent({
+ name: 'NotificationWrapper',
+ setup(_props, { attrs }) {
+ const notiRef = ref();
+ onMounted(() => {
+ callback({
+ notice(noticeProps: NoticeContent) {
+ notiRef.value?.add(noticeProps);
+ },
+ removeNotice(key: Key) {
+ notiRef.value?.remove(key);
+ },
+ destroy() {
+ vueRender(null, div);
+ if (div.parentNode) {
+ div.parentNode.removeChild(div);
+ }
+ },
+ });
+ });
+ return () => {
+ const global = globalConfigForApi;
+ const prefixCls = global.getPrefixCls(name, customizePrefixCls);
+ const rootPrefixCls = global.getRootPrefixCls(customRootPrefixCls, prefixCls);
+ return (
+
+
+
+ );
+ };
+ },
+ });
+
+ const vm = createVNode(Wrapper, props);
+ vm.appContext = appContext || vm.appContext;
+ vueRender(vm, div);
+};
+
+export default Notification;
diff --git a/components/vc-notification/assets/index.less b/components/vc-notification/assets/index.less
deleted file mode 100644
index c020b681c3..0000000000
--- a/components/vc-notification/assets/index.less
+++ /dev/null
@@ -1,95 +0,0 @@
-@notificationPrefixCls: rc-notification;
-
-.@{notificationPrefixCls} {
- position: fixed;
- z-index: 1000;
-
- &-notice {
- padding: 7px 20px 7px 10px;
- border-radius: 3px 3px;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
- border: 0px solid rgba(0, 0, 0, 0);
- background: #fff;
- display: block;
- width: auto;
- line-height: 1.5;
- vertical-align: middle;
- position: relative;
- margin: 10px 0;
-
- &-closable {
- padding-right: 20px;
- }
-
- &-close {
- position: absolute;
- right: 5px;
- top: 3px;
- color: #000;
- cursor: pointer;
- outline: none;
- font-size: 16px;
- font-weight: 700;
- line-height: 1;
- text-shadow: 0 1px 0 #fff;
- filter: alpha(opacity=20);
- opacity: 0.2;
- text-decoration: none;
-
- &-x:after {
- content: '×';
- }
-
- &:hover {
- opacity: 1;
- filter: alpha(opacity=100);
- text-decoration: none;
- }
- }
- }
-
- .fade-effect() {
- animation-duration: 0.3s;
- animation-fill-mode: both;
- animation-timing-function: cubic-bezier(0.55, 0, 0.55, 0.2);
- }
-
- &-fade-enter {
- opacity: 0;
- .fade-effect();
- animation-play-state: paused;
- }
-
- &-fade-leave {
- .fade-effect();
- animation-play-state: paused;
- }
-
- &-fade-enter&-fade-enter-active {
- animation-name: rcNotificationFadeIn;
- animation-play-state: running;
- }
-
- &-fade-leave&-fade-leave-active {
- animation-name: rcDialogFadeOut;
- animation-play-state: running;
- }
-
- @keyframes rcNotificationFadeIn {
- 0% {
- opacity: 0;
- }
- 100% {
- opacity: 1;
- }
- }
-
- @keyframes rcDialogFadeOut {
- 0% {
- opacity: 1;
- }
- 100% {
- opacity: 0;
- }
- }
-}
diff --git a/components/vc-notification/index.js b/components/vc-notification/index.ts
similarity index 67%
rename from components/vc-notification/index.js
rename to components/vc-notification/index.ts
index fdaa1bbe8e..759e48825f 100644
--- a/components/vc-notification/index.js
+++ b/components/vc-notification/index.ts
@@ -1,3 +1,4 @@
-// based on rc-notification 3.3.1
+// based on rc-notification 4.5.7
import Notification from './Notification';
+
export default Notification;
From f92e75a1d935ee74643194ff5864841b9b8828f1 Mon Sep 17 00:00:00 2001
From: tangjinzhou <415800467@qq.com>
Date: Thu, 30 Dec 2021 10:57:15 +0800
Subject: [PATCH 2/4] refactor: message
---
components/message/demo/custom-style.vue | 46 +++++
components/message/demo/index.vue | 3 +
components/message/demo/update.vue | 22 ++-
components/message/index.en-US.md | 26 ++-
components/message/index.tsx | 159 +++++++++++-------
components/message/index.zh-CN.md | 46 +++--
components/message/style/index.less | 11 +-
.../message/style/{index.ts => index.tsx} | 0
components/message/style/rtl.less | 17 ++
components/vc-notification/Notification.tsx | 18 +-
10 files changed, 248 insertions(+), 100 deletions(-)
create mode 100644 components/message/demo/custom-style.vue
rename components/message/style/{index.ts => index.tsx} (100%)
create mode 100644 components/message/style/rtl.less
diff --git a/components/message/demo/custom-style.vue b/components/message/demo/custom-style.vue
new file mode 100644
index 0000000000..3c70c80d34
--- /dev/null
+++ b/components/message/demo/custom-style.vue
@@ -0,0 +1,46 @@
+
+---
+order: 6
+title:
+ zh-CN: 自定义样式
+ en-US: Customized style
+---
+
+## zh-CN
+
+使用 `style` 和 `class` 来定义样式。
+
+## en-US
+
+The `style` and `class` are available to customize Message.
+
+
+
+
+ Customized style
+
+
+
diff --git a/components/message/demo/index.vue b/components/message/demo/index.vue
index 8cc38ab40d..6ad3af47cf 100644
--- a/components/message/demo/index.vue
+++ b/components/message/demo/index.vue
@@ -6,6 +6,7 @@
+