@v-c/notification 2.0.0-rc.1 → 2.0.0-rc.3
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.
|
@@ -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,9 +113,9 @@ 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
|
-
const { key, placement: _itemPlacement, classNames: configClassNames, styles: configStyles, className: configClassName, style: configStyle, ...notificationConfig } = config;
|
|
118
|
+
const { key, placement: _itemPlacement, classNames: configClassNames, styles: configStyles, className: configClassName, style: configStyle, onClose: configOnClose, ...notificationConfig } = config;
|
|
96
119
|
const strKey = String(key);
|
|
97
120
|
const notificationIndex = getIndex(keys.value, key);
|
|
98
121
|
const stackInThreshold = stackEnabled.value && notificationIndex !== void 0 && notificationIndex < (stackParams.threshold?.value ?? 0);
|
|
@@ -115,7 +138,7 @@ var NotificationList = /* @__PURE__ */ defineComponent((props, { attrs }) => {
|
|
|
115
138
|
"notificationIndex": notificationIndex,
|
|
116
139
|
"stackInThreshold": stackInThreshold,
|
|
117
140
|
"onClose": () => {
|
|
118
|
-
|
|
141
|
+
configOnClose?.();
|
|
119
142
|
onNoticeClose?.(key);
|
|
120
143
|
}
|
|
121
144
|
}), null);
|
|
@@ -145,10 +168,7 @@ var NotificationList = /* @__PURE__ */ defineComponent((props, { attrs }) => {
|
|
|
145
168
|
"topNoticeWidth": positionResult.topNoticeWidth,
|
|
146
169
|
"className": ncs?.listContent,
|
|
147
170
|
"style": nss?.listContent
|
|
148
|
-
}, { default: () => [createVNode(TransitionGroup, mergeProps({
|
|
149
|
-
"tag": false,
|
|
150
|
-
"appear": true
|
|
151
|
-
}, motionGroupProps, { "onAfterLeave": checkAllClosed }), _isSlot(_slot = renderItems()) ? _slot : { default: () => [_slot] })] })]);
|
|
171
|
+
}, { default: () => [createVNode(TransitionGroup, mergeProps({ "appear": true }, motionGroupProps, { "onAfterLeave": checkAllClosed }), _isSlot(_slot = renderItems()) ? _slot : { default: () => [_slot] })] })]);
|
|
152
172
|
};
|
|
153
173
|
}, {
|
|
154
174
|
props: {
|
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
|
@@ -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,13 +213,26 @@ 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 = () =>
|
|
193
221
|
keys.value.map((config) => {
|
|
194
|
-
const {
|
|
222
|
+
const {
|
|
223
|
+
key,
|
|
224
|
+
placement: _itemPlacement,
|
|
225
|
+
classNames: configClassNames,
|
|
226
|
+
styles: configStyles,
|
|
227
|
+
className: configClassName,
|
|
228
|
+
style: configStyle,
|
|
229
|
+
// Extract onClose so the spread below does not also bind it.
|
|
230
|
+
// Vue would otherwise merge our `onClose={...}` and the spread's
|
|
231
|
+
// `onClose` into an Array, breaking `props.onClose?.()` in the
|
|
232
|
+
// notice itself.
|
|
233
|
+
onClose: configOnClose,
|
|
234
|
+
...notificationConfig
|
|
235
|
+
} = config
|
|
195
236
|
const strKey = String(key)
|
|
196
237
|
const notificationIndex = getIndex(keys.value, key)
|
|
197
238
|
const stackInThreshold
|
|
@@ -220,7 +261,7 @@ const NotificationList = defineComponent<NotificationListProps>(
|
|
|
220
261
|
notificationIndex={notificationIndex}
|
|
221
262
|
stackInThreshold={stackInThreshold}
|
|
222
263
|
onClose={() => {
|
|
223
|
-
|
|
264
|
+
configOnClose?.()
|
|
224
265
|
onNoticeClose?.(key)
|
|
225
266
|
}}
|
|
226
267
|
/>
|
|
@@ -261,7 +302,6 @@ const NotificationList = defineComponent<NotificationListProps>(
|
|
|
261
302
|
style={nss?.listContent}
|
|
262
303
|
>
|
|
263
304
|
<TransitionGroup
|
|
264
|
-
tag={false as any}
|
|
265
305
|
appear
|
|
266
306
|
{...motionGroupProps}
|
|
267
307
|
onAfterLeave={checkAllClosed}
|
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
|
+
})
|