@v-c/notification 2.0.0-rc.2 → 2.0.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/NotificationList/Content.js +10 -32
- package/dist/NotificationList/index.js +25 -2
- package/dist/Notifications.js +0 -4
- package/package.json +1 -1
- package/src/NotificationList/Content.tsx +11 -1
- package/src/NotificationList/index.tsx +31 -3
- package/src/Notifications.tsx +0 -5
- package/tests/notification.test.tsx +70 -0
- package/vitest.config.ts +3 -1
|
@@ -12,7 +12,7 @@ var Content = /* @__PURE__ */ defineComponent((props, { slots, expose }) => {
|
|
|
12
12
|
const contentPrefixCls = `${listPrefixCls}-content`;
|
|
13
13
|
const contentStyle = {
|
|
14
14
|
...style,
|
|
15
|
-
height
|
|
15
|
+
height: `${height}px`,
|
|
16
16
|
"--top-notificiation-height": `${topNoticeHeight}px`,
|
|
17
17
|
"--top-notificiation-width": `${topNoticeWidth}px`
|
|
18
18
|
};
|
|
@@ -23,38 +23,16 @@ var Content = /* @__PURE__ */ defineComponent((props, { slots, expose }) => {
|
|
|
23
23
|
}, [slots.default?.()]);
|
|
24
24
|
};
|
|
25
25
|
}, {
|
|
26
|
-
props: {
|
|
27
|
-
listPrefixCls: {
|
|
28
|
-
type: String,
|
|
29
|
-
required: true
|
|
30
|
-
},
|
|
31
|
-
height: {
|
|
32
|
-
type: Number,
|
|
33
|
-
required: true
|
|
34
|
-
},
|
|
35
|
-
topNoticeHeight: {
|
|
36
|
-
type: Number,
|
|
37
|
-
required: false,
|
|
38
|
-
default: void 0
|
|
39
|
-
},
|
|
40
|
-
topNoticeWidth: {
|
|
41
|
-
type: Number,
|
|
42
|
-
required: false,
|
|
43
|
-
default: void 0
|
|
44
|
-
},
|
|
45
|
-
className: {
|
|
46
|
-
type: String,
|
|
47
|
-
required: false,
|
|
48
|
-
default: void 0
|
|
49
|
-
},
|
|
50
|
-
style: {
|
|
51
|
-
type: Object,
|
|
52
|
-
required: false,
|
|
53
|
-
default: void 0
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
26
|
name: "NotificationListContent",
|
|
57
|
-
inheritAttrs: false
|
|
27
|
+
inheritAttrs: false,
|
|
28
|
+
props: [
|
|
29
|
+
"listPrefixCls",
|
|
30
|
+
"height",
|
|
31
|
+
"topNoticeHeight",
|
|
32
|
+
"topNoticeWidth",
|
|
33
|
+
"className",
|
|
34
|
+
"style"
|
|
35
|
+
]
|
|
58
36
|
});
|
|
59
37
|
//#endregion
|
|
60
38
|
export { Content as default };
|
|
@@ -5,9 +5,32 @@ import useStack from "../hooks/useStack.js";
|
|
|
5
5
|
import Content from "./Content.js";
|
|
6
6
|
import { TransitionGroup, computed, createVNode, defineComponent, isVNode, mergeProps, ref, shallowRef, toRef, watch, watchEffect } from "vue";
|
|
7
7
|
import { clsx } from "@v-c/util";
|
|
8
|
-
import { getTransitionGroupProps } from "@v-c/util/dist/utils/transition";
|
|
9
8
|
import { unrefElement } from "@v-c/util/dist/vueuse/unref-element";
|
|
10
9
|
//#region src/NotificationList/index.tsx
|
|
10
|
+
/**
|
|
11
|
+
* Map Vue's TransitionGroup enter/leave class hooks onto the rc-motion
|
|
12
|
+
* style class names that antdv-next 6.4.0 notification styles target
|
|
13
|
+
* (-enter-start / -enter-active / -leave-start / -leave-active).
|
|
14
|
+
*
|
|
15
|
+
* The shared @v-c/util getTransitionGroupProps puts -leave-active in the
|
|
16
|
+
* leaveActiveClass, which means the notice jumps straight to opacity:0
|
|
17
|
+
* on leave without animating. Wire each phase to the correct rc-motion
|
|
18
|
+
* suffix so the opacity/transform transition runs.
|
|
19
|
+
*/
|
|
20
|
+
function buildMotionGroupProps(name, override) {
|
|
21
|
+
return {
|
|
22
|
+
name,
|
|
23
|
+
appear: true,
|
|
24
|
+
enterFromClass: `${name} ${name}-enter ${name}-appear ${name}-enter-start ${name}-appear-start`,
|
|
25
|
+
enterActiveClass: `${name} ${name}-enter ${name}-appear`,
|
|
26
|
+
enterToClass: `${name} ${name}-enter ${name}-appear ${name}-enter-active ${name}-appear-active`,
|
|
27
|
+
leaveFromClass: `${name} ${name}-leave ${name}-leave-start`,
|
|
28
|
+
leaveActiveClass: `${name} ${name}-leave`,
|
|
29
|
+
leaveToClass: `${name} ${name}-leave ${name}-leave-active`,
|
|
30
|
+
moveClass: `${name} ${name}-move`,
|
|
31
|
+
...override
|
|
32
|
+
};
|
|
33
|
+
}
|
|
11
34
|
function _isSlot(s) {
|
|
12
35
|
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
|
|
13
36
|
}
|
|
@@ -90,7 +113,7 @@ var NotificationList = /* @__PURE__ */ defineComponent((props, { attrs }) => {
|
|
|
90
113
|
const listPrefixCls = `${prefixCls}-list`;
|
|
91
114
|
const positionResult = position.value;
|
|
92
115
|
let motionGroupProps = {};
|
|
93
|
-
if (placementMotion.value) motionGroupProps =
|
|
116
|
+
if (placementMotion.value?.name) motionGroupProps = buildMotionGroupProps(placementMotion.value.name, placementMotion.value);
|
|
94
117
|
const renderItems = () => keys.value.map((config) => {
|
|
95
118
|
const { key, placement: _itemPlacement, classNames: configClassNames, styles: configStyles, className: configClassName, style: configStyle, onClose: configOnClose, ...notificationConfig } = config;
|
|
96
119
|
const strKey = String(key);
|
package/dist/Notifications.js
CHANGED
|
@@ -8,10 +8,6 @@ var defaults = { prefixCls: "vc-notification" };
|
|
|
8
8
|
var Notifications = /* @__PURE__ */ defineComponent((props, { expose }) => {
|
|
9
9
|
const configList = shallowRef([]);
|
|
10
10
|
const onNoticeClose = (key) => {
|
|
11
|
-
const config = configList.value.find((item) => item.key === key);
|
|
12
|
-
const closable = config?.closable;
|
|
13
|
-
(closable && typeof closable === "object" ? closable : null)?.onClose?.();
|
|
14
|
-
config?.onClose?.();
|
|
15
11
|
configList.value = configList.value.filter((item) => item.key !== key);
|
|
16
12
|
};
|
|
17
13
|
expose({
|
package/package.json
CHANGED
|
@@ -39,9 +39,14 @@ const Content = defineComponent<ContentProps>(
|
|
|
39
39
|
prevHeight = height
|
|
40
40
|
|
|
41
41
|
const contentPrefixCls = `${listPrefixCls}-content`
|
|
42
|
+
// Force height to a string so Vue's style patcher always re-applies the
|
|
43
|
+
// unit. Passing a plain number (e.g. 0 → 216) was getting silently
|
|
44
|
+
// skipped during patch — the CSS variables on the same vnode style
|
|
45
|
+
// were applied, but `height: 216` was not patched onto the DOM until
|
|
46
|
+
// a manual `inst.update()` was invoked.
|
|
42
47
|
const contentStyle: ContentStyle = {
|
|
43
48
|
...style,
|
|
44
|
-
height
|
|
49
|
+
height: `${height}px`,
|
|
45
50
|
'--top-notificiation-height': `${topNoticeHeight}px`,
|
|
46
51
|
'--top-notificiation-width': `${topNoticeWidth}px`,
|
|
47
52
|
}
|
|
@@ -60,6 +65,11 @@ const Content = defineComponent<ContentProps>(
|
|
|
60
65
|
{
|
|
61
66
|
name: 'NotificationListContent',
|
|
62
67
|
inheritAttrs: false,
|
|
68
|
+
// Declare runtime props so Vue tracks reactive reads inside the render
|
|
69
|
+
// closure. Without this, `props.height` in `const { height } = props`
|
|
70
|
+
// does not subscribe to updates, so the rendered `height: 0px` stays
|
|
71
|
+
// stale even after position recomputes with measured node sizes.
|
|
72
|
+
props: ['listPrefixCls', 'height', 'topNoticeHeight', 'topNoticeWidth', 'className', 'style'] as any,
|
|
63
73
|
},
|
|
64
74
|
)
|
|
65
75
|
|
|
@@ -7,9 +7,37 @@ import type {
|
|
|
7
7
|
NotificationStyles as NoticeStyles,
|
|
8
8
|
} from '../Notification'
|
|
9
9
|
import { clsx } from '@v-c/util'
|
|
10
|
-
import { getTransitionGroupProps } from '@v-c/util/dist/utils/transition'
|
|
11
10
|
import { unrefElement } from '@v-c/util/dist/vueuse/unref-element'
|
|
12
11
|
import { computed, defineComponent, ref, shallowRef, toRef, TransitionGroup, watch, watchEffect } from 'vue'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Map Vue's TransitionGroup enter/leave class hooks onto the rc-motion
|
|
15
|
+
* style class names that antdv-next 6.4.0 notification styles target
|
|
16
|
+
* (-enter-start / -enter-active / -leave-start / -leave-active).
|
|
17
|
+
*
|
|
18
|
+
* The shared @v-c/util getTransitionGroupProps puts -leave-active in the
|
|
19
|
+
* leaveActiveClass, which means the notice jumps straight to opacity:0
|
|
20
|
+
* on leave without animating. Wire each phase to the correct rc-motion
|
|
21
|
+
* suffix so the opacity/transform transition runs.
|
|
22
|
+
*/
|
|
23
|
+
function buildMotionGroupProps(name: string, override?: Partial<TransitionGroupProps>): TransitionGroupProps {
|
|
24
|
+
return {
|
|
25
|
+
name,
|
|
26
|
+
appear: true,
|
|
27
|
+
// ENTER: from = opacity 0 (-enter-start / -appear-start)
|
|
28
|
+
// to = opacity 1 (-enter-active / -appear-active)
|
|
29
|
+
enterFromClass: `${name} ${name}-enter ${name}-appear ${name}-enter-start ${name}-appear-start`,
|
|
30
|
+
enterActiveClass: `${name} ${name}-enter ${name}-appear`,
|
|
31
|
+
enterToClass: `${name} ${name}-enter ${name}-appear ${name}-enter-active ${name}-appear-active`,
|
|
32
|
+
// LEAVE: from = opacity 1 (-leave-start)
|
|
33
|
+
// to = opacity 0 (-leave-active)
|
|
34
|
+
leaveFromClass: `${name} ${name}-leave ${name}-leave-start`,
|
|
35
|
+
leaveActiveClass: `${name} ${name}-leave`,
|
|
36
|
+
leaveToClass: `${name} ${name}-leave ${name}-leave-active`,
|
|
37
|
+
moveClass: `${name} ${name}-move`,
|
|
38
|
+
...override,
|
|
39
|
+
}
|
|
40
|
+
}
|
|
13
41
|
import useListPosition from '../hooks/useListPosition'
|
|
14
42
|
import useStack from '../hooks/useStack'
|
|
15
43
|
import Notification from '../Notification'
|
|
@@ -185,8 +213,8 @@ const NotificationList = defineComponent<NotificationListProps>(
|
|
|
185
213
|
const positionResult = position.value
|
|
186
214
|
|
|
187
215
|
let motionGroupProps: TransitionGroupProps = {}
|
|
188
|
-
if (placementMotion.value) {
|
|
189
|
-
motionGroupProps =
|
|
216
|
+
if (placementMotion.value?.name) {
|
|
217
|
+
motionGroupProps = buildMotionGroupProps(placementMotion.value.name, placementMotion.value)
|
|
190
218
|
}
|
|
191
219
|
|
|
192
220
|
const renderItems = () =>
|
package/src/Notifications.tsx
CHANGED
|
@@ -42,11 +42,6 @@ const Notifications = defineComponent<NotificationsProps>(
|
|
|
42
42
|
const configList = shallowRef<NotificationListConfig[]>([])
|
|
43
43
|
|
|
44
44
|
const onNoticeClose = (key: Key) => {
|
|
45
|
-
const config = configList.value.find(item => item.key === key)
|
|
46
|
-
const closable = config?.closable
|
|
47
|
-
const closableObj = closable && typeof closable === 'object' ? closable : null
|
|
48
|
-
closableObj?.onClose?.()
|
|
49
|
-
config?.onClose?.()
|
|
50
45
|
configList.value = configList.value.filter(item => item.key !== key)
|
|
51
46
|
}
|
|
52
47
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils'
|
|
2
|
+
import { nextTick } from 'vue'
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
+
import Notifications from '../src/Notifications'
|
|
5
|
+
|
|
6
|
+
describe('notification', () => {
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
document.body.innerHTML = ''
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('calls close callbacks once when notice close button is clicked', async () => {
|
|
12
|
+
const onClose = vi.fn()
|
|
13
|
+
const closableOnClose = vi.fn()
|
|
14
|
+
const wrapper = mount(Notifications, {
|
|
15
|
+
props: {
|
|
16
|
+
container: document.body,
|
|
17
|
+
},
|
|
18
|
+
attachTo: document.body,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
wrapper.vm.open({
|
|
22
|
+
key: 'notice',
|
|
23
|
+
title: 'Notice',
|
|
24
|
+
duration: false,
|
|
25
|
+
closable: {
|
|
26
|
+
closeIcon: 'x',
|
|
27
|
+
onClose: closableOnClose,
|
|
28
|
+
},
|
|
29
|
+
onClose,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
await nextTick()
|
|
33
|
+
await nextTick()
|
|
34
|
+
await document.querySelector<HTMLButtonElement>('.vc-notification-notice-close')!.click()
|
|
35
|
+
await nextTick()
|
|
36
|
+
|
|
37
|
+
expect(closableOnClose).toHaveBeenCalledTimes(1)
|
|
38
|
+
expect(onClose).toHaveBeenCalledTimes(1)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('does not call notice close callbacks when closed by api', async () => {
|
|
42
|
+
const onClose = vi.fn()
|
|
43
|
+
const closableOnClose = vi.fn()
|
|
44
|
+
const wrapper = mount(Notifications, {
|
|
45
|
+
props: {
|
|
46
|
+
container: document.body,
|
|
47
|
+
},
|
|
48
|
+
attachTo: document.body,
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
wrapper.vm.open({
|
|
52
|
+
key: 'notice',
|
|
53
|
+
title: 'Notice',
|
|
54
|
+
duration: false,
|
|
55
|
+
closable: {
|
|
56
|
+
closeIcon: 'x',
|
|
57
|
+
onClose: closableOnClose,
|
|
58
|
+
},
|
|
59
|
+
onClose,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
await nextTick()
|
|
63
|
+
await nextTick()
|
|
64
|
+
wrapper.vm.close('notice')
|
|
65
|
+
await nextTick()
|
|
66
|
+
|
|
67
|
+
expect(closableOnClose).not.toHaveBeenCalled()
|
|
68
|
+
expect(onClose).not.toHaveBeenCalled()
|
|
69
|
+
})
|
|
70
|
+
})
|