Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/components/I9kModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ function isShown(element: HTMLDialogElement) {

function show() {
const element = dialog.value;
if (unmounting || !element || isShown(element)) return;
// The dialog can also leave the document while the modal stays mounted (a
// removed subtree, a page cached by <KeepAlive>), and showModal() throws on a
// disconnected element.
if (unmounting || !element || !element.isConnected || isShown(element)) return;
// Kept when the dialog is shown again after the browser closed it, so focus
// still returns to the element that opened it, not to where focus landed.
if (!returnFocus) {
Expand Down
8 changes: 8 additions & 0 deletions tests/I9kModal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ describe('I9kModal with a native dialog', () => {
expect(document.activeElement).toBe(opener);
});

it('does not show a dialog that left the page before the queued show ran', async () => {
const wrapper = mountModal({ open: false });
(wrapper.get('dialog').element as HTMLDialogElement).remove();
await wrapper.setProps({ open: true });
await wrapper.vm.$nextTick();
expect(prototype.showModal).not.toHaveBeenCalled();
});

// A route change in an app: the old page stays mounted under <Suspense>
// while the next one loads, and re-rendering the modal then (here its
// `dismissible` coming back once a save ends) leaves Vue a ref update that
Expand Down
Loading