Merge branch 'fork/dream-weave/fix/popup-route-reentry'
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import type { App } from 'vue';
|
||||
|
||||
import { createApp, defineComponent, h, nextTick } from 'vue';
|
||||
|
||||
import { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';
|
||||
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { useVbenDrawer } from '../use-drawer';
|
||||
|
||||
vi.mock('@vben-core/preferences', () => ({
|
||||
usePreferences: () => ({
|
||||
globalEscapeShortcutKey: { value: true },
|
||||
}),
|
||||
}));
|
||||
|
||||
let activeApp: App | undefined;
|
||||
|
||||
async function mountPreopenedDrawer() {
|
||||
const mainContent = document.createElement('main');
|
||||
mainContent.id = ELEMENT_ID_MAIN_CONTENT;
|
||||
mainContent.innerHTML = '<div><div></div></div>';
|
||||
document.body.append(mainContent);
|
||||
|
||||
const Consumer = defineComponent(() => {
|
||||
const [Drawer, drawerApi] = useVbenDrawer({ appendToMain: true });
|
||||
drawerApi.open();
|
||||
return () => h(Drawer);
|
||||
});
|
||||
const host = document.createElement('div');
|
||||
document.body.append(host);
|
||||
|
||||
activeApp = createApp(() => h(Consumer));
|
||||
activeApp.mount(host);
|
||||
await nextTick();
|
||||
|
||||
return mainContent;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
activeApp?.unmount();
|
||||
activeApp = undefined;
|
||||
document.body.innerHTML = '';
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('vben drawer', () => {
|
||||
it('mounts an initially open drawer directly in the main content', async () => {
|
||||
const mainContent = await mountPreopenedDrawer();
|
||||
const dialog = document.querySelector('[role="dialog"]');
|
||||
|
||||
expect(dialog).toBeInstanceOf(HTMLElement);
|
||||
if (!(dialog instanceof HTMLElement)) return;
|
||||
expect(dialog.parentElement).toBe(mainContent);
|
||||
});
|
||||
|
||||
it('shows a drawer that is opened before mounting', async () => {
|
||||
await mountPreopenedDrawer();
|
||||
const dialog = document.querySelector('[role="dialog"]');
|
||||
|
||||
expect(dialog).toBeInstanceOf(HTMLElement);
|
||||
if (!(dialog instanceof HTMLElement)) return;
|
||||
expect(dialog.classList.contains('hidden')).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -148,9 +148,7 @@ function handleFocusOutside(e: Event) {
|
||||
}
|
||||
|
||||
const getAppendTo = computed(() => {
|
||||
return appendToMain.value
|
||||
? `#${ELEMENT_ID_MAIN_CONTENT}>div:not(.absolute)>div`
|
||||
: undefined;
|
||||
return appendToMain.value ? `#${ELEMENT_ID_MAIN_CONTENT}` : undefined;
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -167,6 +165,7 @@ watch(
|
||||
hasOpened.value = true;
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
function handleClosed() {
|
||||
isClosed.value = true;
|
||||
|
||||
102
packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal.test.ts
Normal file
102
packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal.test.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import type { App } from 'vue';
|
||||
|
||||
import { createApp, defineComponent, h, nextTick, onMounted } from 'vue';
|
||||
|
||||
import { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';
|
||||
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { useVbenModal } from '../use-modal';
|
||||
|
||||
vi.mock('@vben-core/preferences', () => ({
|
||||
usePreferences: () => ({
|
||||
globalEscapeShortcutKey: { value: true },
|
||||
}),
|
||||
}));
|
||||
|
||||
let activeApp: App | undefined;
|
||||
|
||||
async function mountModal() {
|
||||
const mainContent = document.createElement('main');
|
||||
mainContent.id = ELEMENT_ID_MAIN_CONTENT;
|
||||
mainContent.innerHTML = '<div><div></div></div>';
|
||||
document.body.append(mainContent);
|
||||
|
||||
const Consumer = defineComponent(() => {
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
appendToMain: true,
|
||||
draggable: true,
|
||||
title: 'Draggable modal',
|
||||
});
|
||||
onMounted(() => {
|
||||
modalApi.open();
|
||||
});
|
||||
return () => h(Modal);
|
||||
});
|
||||
const host = document.createElement('div');
|
||||
document.body.append(host);
|
||||
|
||||
activeApp = createApp(() => h(Consumer));
|
||||
activeApp.mount(host);
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
return mainContent;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
activeApp?.unmount();
|
||||
activeApp = undefined;
|
||||
document.body.innerHTML = '';
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('vben modal', () => {
|
||||
it('mounts an open modal directly in the main content', async () => {
|
||||
const mainContent = await mountModal();
|
||||
const dialog = document.querySelector('[role="dialog"]');
|
||||
const overlay = document.querySelector('[data-dismissable-modal]');
|
||||
|
||||
expect(dialog).toBeInstanceOf(HTMLElement);
|
||||
if (!(dialog instanceof HTMLElement)) return;
|
||||
expect(overlay).toBeInstanceOf(HTMLElement);
|
||||
if (!(overlay instanceof HTMLElement)) return;
|
||||
expect(dialog.parentElement).toBe(mainContent);
|
||||
expect(overlay.parentElement).toBe(mainContent);
|
||||
});
|
||||
|
||||
it('constrains dragging to the main content', async () => {
|
||||
const mainContent = await mountModal();
|
||||
const dialog = document.querySelector('[role="dialog"]');
|
||||
const header = document.querySelector('.cursor-move');
|
||||
|
||||
expect(dialog).toBeInstanceOf(HTMLElement);
|
||||
if (!(dialog instanceof HTMLElement)) return;
|
||||
expect(header).toBeInstanceOf(HTMLElement);
|
||||
if (!(header instanceof HTMLElement)) return;
|
||||
|
||||
vi.spyOn(mainContent, 'getBoundingClientRect').mockReturnValue(
|
||||
new DOMRect(100, 100, 800, 600),
|
||||
);
|
||||
vi.spyOn(dialog, 'getBoundingClientRect').mockReturnValue(
|
||||
new DOMRect(300, 200, 400, 300),
|
||||
);
|
||||
|
||||
header.dispatchEvent(
|
||||
new MouseEvent('mousedown', {
|
||||
bubbles: true,
|
||||
clientX: 400,
|
||||
clientY: 300,
|
||||
}),
|
||||
);
|
||||
document.dispatchEvent(
|
||||
new MouseEvent('mousemove', {
|
||||
clientX: 1400,
|
||||
clientY: 1300,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(dialog.style.transform).toBe('translate(200px, 200px)');
|
||||
document.dispatchEvent(new MouseEvent('mouseup'));
|
||||
});
|
||||
});
|
||||
@@ -107,9 +107,7 @@ const shouldCentered = computed(
|
||||
);
|
||||
|
||||
const getAppendTo = computed(() => {
|
||||
return appendToMain.value
|
||||
? `#${ELEMENT_ID_MAIN_CONTENT}>div:not(.absolute)>div`
|
||||
: undefined;
|
||||
return appendToMain.value ? `#${ELEMENT_ID_MAIN_CONTENT}` : undefined;
|
||||
});
|
||||
|
||||
const { dragging, transform } = useModalDraggable(
|
||||
|
||||
Reference in New Issue
Block a user