From 585839a37d590037dd14f018a390b0bcc8aa30a3 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 26 Jul 2022 15:16:37 -0400 Subject: [PATCH 1/3] =?UTF-8?q?Don=E2=80=99t=20overwrite=20`element.focus`?= =?UTF-8?q?=20on=20popover=20panels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/@headlessui-vue/src/components/popover/popover.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@headlessui-vue/src/components/popover/popover.ts b/packages/@headlessui-vue/src/components/popover/popover.ts index 226220f4c..61c425c1e 100644 --- a/packages/@headlessui-vue/src/components/popover/popover.ts +++ b/packages/@headlessui-vue/src/components/popover/popover.ts @@ -14,7 +14,7 @@ import { } from 'vue' import { match } from '../../utils/match' -import { render, Features } from '../../utils/render' +import { render, omit, Features } from '../../utils/render' import { useId } from '../../hooks/use-id' import { Keys } from '../../keyboard' import { @@ -620,7 +620,7 @@ export let PopoverPanel = defineComponent({ return render({ ourProps, - theirProps: { ...attrs, ...props }, + theirProps: { ...attrs, ...omit(props, ['focus']) }, attrs, slot, slots: { From b2fb51f0b8a69725f42f5c543424ce7df7bd973e Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 26 Jul 2022 15:20:13 -0400 Subject: [PATCH 2/3] Update changelog --- packages/@headlessui-vue/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/@headlessui-vue/CHANGELOG.md b/packages/@headlessui-vue/CHANGELOG.md index cdaaf530a..8890b56c4 100644 --- a/packages/@headlessui-vue/CHANGELOG.md +++ b/packages/@headlessui-vue/CHANGELOG.md @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improve outside click on Safari iOS ([#1712](https://github.com/tailwindlabs/headlessui/pull/1712)) - Improve event handler merging ([#1715](https://github.com/tailwindlabs/headlessui/pull/1715)) - Fix incorrect scrolling to the bottom when opening a `Dialog` ([#1716](https://github.com/tailwindlabs/headlessui/pull/1716)) +- Don't overwrite `element.focus()` on `` ([#1719](https://github.com/tailwindlabs/headlessui/pull/1719)) ## [1.6.7] - 2022-07-12 From d7dde4a31f8347872ef0e7bdf8c69810766e7e4e Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 26 Jul 2022 15:56:15 -0400 Subject: [PATCH 3/3] Add test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test isn’t exactly right for JSDOM but it does mirror what we would do in the browser to reproduce the problem --- .../src/components/dialog/dialog.test.tsx | 67 +++++++++++++++++++ .../src/components/dialog/dialog.test.ts | 67 +++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/packages/@headlessui-react/src/components/dialog/dialog.test.tsx b/packages/@headlessui-react/src/components/dialog/dialog.test.tsx index 985f4050f..3cedae9c3 100644 --- a/packages/@headlessui-react/src/components/dialog/dialog.test.tsx +++ b/packages/@headlessui-react/src/components/dialog/dialog.test.tsx @@ -2,16 +2,20 @@ import React, { createElement, useRef, useState, Fragment } from 'react' import { render } from '@testing-library/react' import { Dialog } from './dialog' +import { Popover } from '../popover/popover' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' import { DialogState, + PopoverState, assertDialog, assertDialogDescription, assertDialogOverlay, assertDialogTitle, + assertPopoverPanel, getDialog, getDialogOverlay, getDialogBackdrop, + getPopoverButton, getByText, assertActiveElement, getDialogs, @@ -519,6 +523,69 @@ describe('Rendering', () => { }) describe('Composition', () => { + it( + 'should be possible to open a dialog from inside a Popover (and then close it)', + suppressConsoleLogs(async () => { + function Example() { + let [isDialogOpen, setIsDialogOpen] = useState(false) + + return ( +
+ + Open Popover + +
setIsDialogOpen(true)}> + Open dialog +
+
+
+ + + + + + +
+ ) + } + + render() + + await nextFrame() + + // Nothing is open initially + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }) + assertDialog({ state: DialogState.InvisibleUnmounted }) + assertActiveElement(document.body) + + // Open the popover + await click(getPopoverButton()) + + // The popover should be open but the dialog should not + assertPopoverPanel({ state: PopoverState.Visible }) + assertDialog({ state: DialogState.InvisibleUnmounted }) + assertActiveElement(getPopoverButton()) + + // Open the dialog from inside the popover + await click(document.getElementById('openDialog')) + + // The dialog should be open but the popover should not + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }) + assertDialog({ state: DialogState.Visible }) + assertActiveElement(document.getElementById('closeDialog')) + + // Close the dialog from inside itself + await click(document.getElementById('closeDialog')) + + // Nothing should be open + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }) + assertDialog({ state: DialogState.InvisibleUnmounted }) + assertActiveElement(getPopoverButton()) + }) + ) + it( 'should be possible to open the Dialog via a Transition component', suppressConsoleLogs(async () => { diff --git a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts index c0d3c668d..dba16d14c 100644 --- a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts +++ b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts @@ -9,17 +9,22 @@ import { DialogTitle, DialogDescription, } from './dialog' + +import { Popover, PopoverPanel, PopoverButton } from '../popover/popover' import { TransitionRoot } from '../transitions/transition' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' import { DialogState, + PopoverState, assertDialog, assertDialogDescription, assertDialogOverlay, assertDialogTitle, + assertPopoverPanel, getDialog, getDialogOverlay, getDialogBackdrop, + getPopoverButton, getByText, assertActiveElement, getDialogs, @@ -680,6 +685,68 @@ describe('Rendering', () => { }) describe('Composition', () => { + it( + 'should be possible to open a dialog from inside a Popover (and then close it)', + suppressConsoleLogs(async () => { + renderTemplate({ + components: { Popover, PopoverButton, PopoverPanel }, + template: ` +
+ + Open Popover + +
Open dialog
+
+
+ + + + + + +
+ `, + setup() { + let isDialogOpen = ref(false) + return { + isDialogOpen, + } + }, + }) + + await nextFrame() + + // Nothing is open initially + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }) + assertDialog({ state: DialogState.InvisibleUnmounted }) + assertActiveElement(document.body) + + // Open the popover + await click(getPopoverButton()) + + // The popover should be open but the dialog should not + assertPopoverPanel({ state: PopoverState.Visible }) + assertDialog({ state: DialogState.InvisibleUnmounted }) + assertActiveElement(getPopoverButton()) + + // Open the dialog from inside the popover + await click(document.getElementById('openDialog')) + + // The dialog should be open but the popover should not + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }) + assertDialog({ state: DialogState.Visible }) + assertActiveElement(document.getElementById('closeDialog')) + + // Close the dialog from inside itself + await click(document.getElementById('closeDialog')) + + // Nothing should be open + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }) + assertDialog({ state: DialogState.InvisibleUnmounted }) + assertActiveElement(getPopoverButton()) + }) + ) + it( 'should be possible to open the Dialog via a Transition component', suppressConsoleLogs(async () => {