From 0b8750eafbc5a4bebb6a59e844fb2732ab732901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BF=9E=E5=8F=AF=20=C2=B7=20YU=20KE?= <1798456934@qq.com> Date: Fri, 28 Aug 2026 15:49:13 +0800 Subject: [PATCH] feat(@vben-core/popup-ui): add extra header slot to modal (#8310) Allow custom content to be rendered in the modal header, positioned to the left of the fullscreen toggle button, via a new `extra` slot. Mirrors the existing `extra` slot in the drawer component. Co-authored-by: EvoX --- .changeset/gold-donkeys-modal-extra.md | 5 +++ .../src/modal/__tests__/modal.test.ts | 37 +++++++++++++++++++ .../@core/ui-kit/popup-ui/src/modal/modal.vue | 20 ++++++---- 3 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 .changeset/gold-donkeys-modal-extra.md diff --git a/.changeset/gold-donkeys-modal-extra.md b/.changeset/gold-donkeys-modal-extra.md new file mode 100644 index 000000000..0b5b17dd0 --- /dev/null +++ b/.changeset/gold-donkeys-modal-extra.md @@ -0,0 +1,5 @@ +--- +'@vben-core/popup-ui': minor +--- + +feat(@vben-core/popup-ui): support custom content in modal header via extra slot diff --git a/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal.test.ts b/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal.test.ts index 20a95bc31..9c52bd549 100644 --- a/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal.test.ts +++ b/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal.test.ts @@ -106,6 +106,43 @@ describe('vben modal', () => { document.dispatchEvent(new MouseEvent('mouseup')); }); + it('renders custom content in the extra header slot', async () => { + const mainContent = document.createElement('main'); + mainContent.id = ELEMENT_ID_MAIN_CONTENT; + mainContent.innerHTML = '
'; + document.body.append(mainContent); + + const Consumer = defineComponent(() => { + const [Modal, modalApi] = useVbenModal({ + appendToMain: true, + fullscreenButton: true, + title: 'Slot modal', + }); + onMounted(() => { + modalApi.open(); + }); + return () => + h(Modal, null, { + extra: () => h('span', { class: 'extra-slot-marker' }, 'Custom'), + }); + }); + const host = document.createElement('div'); + document.body.append(host); + activeApp = createApp(() => h(Consumer)); + activeApp.mount(host); + await nextTick(); + await nextTick(); + + const marker = document.querySelector('.extra-slot-marker'); + expect(marker).toBeInstanceOf(HTMLElement); + if (!(marker instanceof HTMLElement)) return; + expect(marker.textContent?.trim()).toBe('Custom'); + // extra slot 应渲染在 fullscreen 按钮容器内,与全屏按钮同排 + const container = marker.closest('.absolute'); + expect(container).toBeInstanceOf(HTMLElement); + expect(mainContent.contains(container)).toBe(true); + }); + it('fires onClosed via the fallback when no animation event arrives', async () => { vi.useFakeTimers({ toFake: [ diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal.vue b/packages/@core/ui-kit/popup-ui/src/modal/modal.vue index 4a3e44537..ebfac5a90 100644 --- a/packages/@core/ui-kit/popup-ui/src/modal/modal.vue +++ b/packages/@core/ui-kit/popup-ui/src/modal/modal.vue @@ -319,14 +319,20 @@ function handleClosed() { - - - - + + + + + +