@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.
@@ -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 = getTransitionGroupProps(placementMotion.value.name, placementMotion.value);
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);
@@ -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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@v-c/notification",
3
3
  "type": "module",
4
- "version": "2.0.0-rc.2",
4
+ "version": "2.0.0-rc.4",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -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 = getTransitionGroupProps(placementMotion.value.name!, placementMotion.value)
216
+ if (placementMotion.value?.name) {
217
+ motionGroupProps = buildMotionGroupProps(placementMotion.value.name, placementMotion.value)
190
218
  }
191
219
 
192
220
  const renderItems = () =>
@@ -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
+ })
package/vitest.config.ts CHANGED
@@ -4,6 +4,8 @@ import configShared from '../../vitest.config'
4
4
  export default mergeConfig(
5
5
  configShared,
6
6
  defineProject({
7
-
7
+ test: {
8
+ environment: 'jsdom',
9
+ },
8
10
  }),
9
11
  )