diff --git a/docs/en-US/component/notification.md b/docs/en-US/component/notification.md index 15ecb1ae41..6dcefef9f3 100644 --- a/docs/en-US/component/notification.md +++ b/docs/en-US/component/notification.md @@ -100,7 +100,7 @@ ElNotification({ }) ``` -In this case you should call `ElNotification(options)`. We have also registered methods for different types, e.g. `ElNotification.success(options)`. You can call `ElNotification.closeAll()` to manually close all the instances. +In this case you should call `ElNotification(options)`. We have also registered methods for different types, e.g. `ElNotification.success(options)`. You can call `ElNotification.closeAll()` to manually close all the instances. In ^(2.10.5) you can manually update the offsets of all instances in a specific direction by calling `ElNotification.updateOffsets(position)`. ## App context inheritance > 2.0.4 diff --git a/packages/components/notification/__tests__/notify.test.tsx b/packages/components/notification/__tests__/notify.test.tsx index 5879d7def5..9fb9798699 100644 --- a/packages/components/notification/__tests__/notify.test.tsx +++ b/packages/components/notification/__tests__/notify.test.tsx @@ -1,7 +1,8 @@ import { createApp, nextTick } from 'vue' import { afterEach, describe, expect, it, vi } from 'vitest' import { rAF } from '@element-plus/test-utils/tick' -import Notification, { closeAll } from '../src/notify' +import Notification, { closeAll, updateOffsets } from '../src/notify' +import defineGetter from '@element-plus/test-utils/define-getter' import type { NotificationHandle } from '../src/notification' import type { VNode } from 'vue' @@ -89,6 +90,59 @@ describe('Notification on command', () => { expect(document.querySelectorAll(selector).length).toBe(0) }) + it('it should update offsets notifications', async () => { + // the gap size between each notification + const GAP_SIZE = 16 + const height = 100 + const notifications: NotificationHandle[] = [] + const cleanups: (() => void)[] = [] + + for (let i = 0; i < 4; i++) { + notifications.push(Notification({ duration: 0 })) + + await nextTick() + + const el = document.querySelector(`${selector}:nth-child(${i + 1})`)! + + // mocking offsetHeight + cleanups.push( + defineGetter(el, 'offsetHeight', function (this: HTMLElement) { + return Number.parseFloat(this.style.height) || height + }) + ) + } + + await rAF() + + const notificationEls = Array.from( + document.querySelectorAll(selector) + ) + + expect(notificationEls.length).toBe(4) + + const getOffsets = () => notificationEls.map((el) => el?.style.top || '0') + + expect(getOffsets()).toEqual( + Array.from({ length: 4 }).map( + (_, i) => `${(i + 1) * GAP_SIZE + i * height}px` + ) + ) + + notificationEls[0]?.style.setProperty('height', '150px') + + updateOffsets('top-right') + + await rAF() + + expect(getOffsets()).toEqual( + Array.from({ length: 4 }).map( + (_, i) => `${(i + 1) * GAP_SIZE + i * height + (i > 0 ? 50 : 0)}px` + ) + ) + + cleanups.forEach((fn) => fn()) + }) + it('it should be able to render all types notification', () => { for (const type of ['success', 'warning', 'error', 'info'] as const) { Notification[type]({}) diff --git a/packages/components/notification/src/notification.ts b/packages/components/notification/src/notification.ts index e50614a589..1fc7cd32f8 100644 --- a/packages/components/notification/src/notification.ts +++ b/packages/components/notification/src/notification.ts @@ -163,6 +163,7 @@ export interface NotifyFn { appContext?: null | AppContext ): NotificationHandle closeAll(): void + updateOffsets(position?: NotificationOptions['position']): void _context: AppContext | null } diff --git a/packages/components/notification/src/notify.ts b/packages/components/notification/src/notify.ts index 618138f6d6..a2ced312f7 100644 --- a/packages/components/notification/src/notify.ts +++ b/packages/components/notification/src/notify.ts @@ -170,7 +170,19 @@ export function closeAll(): void { } } +export function updateOffsets( + position: NotificationOptions['position'] = 'top-right' +) { + let verticalOffset = notifications[position][0]?.vm.props?.offset || 0 + + for (const { vm } of notifications[position]) { + vm.component!.props.offset = verticalOffset + verticalOffset += (vm.el?.offsetHeight || 0) + GAP_SIZE + } +} + notify.closeAll = closeAll +notify.updateOffsets = updateOffsets notify._context = null export default notify as Notify