From 5af3bd4b7164a0205ac70c179d8e9651afbb0a72 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 15 Jul 2022 11:43:45 -0400 Subject: [PATCH] Don't scroll lock when a Transition + Dialog is mounted but hidden (#1681) * Refer to context for initial Transition Tree state * Update changelog --- packages/@headlessui-react/CHANGELOG.md | 1 + .../src/components/dialog/dialog.test.tsx | 40 ++++++++++++++- .../src/components/transitions/transition.tsx | 4 +- .../src/components/dialog/dialog.test.ts | 51 +++++++++++++++++++ 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index f4966128a7..70eff7a325 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Close `Menu` component when using `tab` key ([#1673](https://github.com/tailwindlabs/headlessui/pull/1673)) - Resync input when display value changes ([#1679](https://github.com/tailwindlabs/headlessui/pull/1679)) - Ensure controlled `Tabs` don't change automagically ([#1680](https://github.com/tailwindlabs/headlessui/pull/1680)) +- Don't scroll lock when a Transition + Dialog is mounted but hidden ([#1681](https://github.com/tailwindlabs/headlessui/pull/1681)) ## [1.6.6] - 2022-07-07 diff --git a/packages/@headlessui-react/src/components/dialog/dialog.test.tsx b/packages/@headlessui-react/src/components/dialog/dialog.test.tsx index fe12492c9e..bf339ef86a 100644 --- a/packages/@headlessui-react/src/components/dialog/dialog.test.tsx +++ b/packages/@headlessui-react/src/components/dialog/dialog.test.tsx @@ -1,4 +1,4 @@ -import React, { createElement, useRef, useState } from 'react' +import React, { createElement, useRef, useState, Fragment } from 'react' import { render } from '@testing-library/react' import { Dialog } from './dialog' @@ -270,6 +270,44 @@ describe('Rendering', () => { expect(document.documentElement.style.overflow).toBe('hidden') }) ) + + it( + 'should wait to add a scroll lock to the html tag when unmount is false in a Transition', + suppressConsoleLogs(async () => { + function Example() { + let [isOpen, setIsOpen] = useState(false) + + return ( + <> + + + + setIsOpen(false)} unmount={false}> + + + + + + + ) + } + + render() + + // No overflow yet + expect(document.documentElement.style.overflow).toBe('') + + let btn = document.getElementById('trigger') + + // Open the dialog + await click(btn) + + // Expect overflow + expect(document.documentElement.style.overflow).toBe('hidden') + }) + ) }) describe('Dialog.Overlay', () => { diff --git a/packages/@headlessui-react/src/components/transitions/transition.tsx b/packages/@headlessui-react/src/components/transitions/transition.tsx index 09fd8f00e7..5227b8f340 100644 --- a/packages/@headlessui-react/src/components/transitions/transition.tsx +++ b/packages/@headlessui-react/src/components/transitions/transition.tsx @@ -209,10 +209,12 @@ let TransitionChild = forwardRefWithAs(function TransitionChild< } = props as typeof props let container = useRef(null) let transitionRef = useSyncRefs(container, ref) - let [state, setState] = useState(TreeStates.Visible) let strategy = rest.unmount ? RenderStrategy.Unmount : RenderStrategy.Hidden let { show, appear, initial } = useTransitionContext() + + let [state, setState] = useState(show ? TreeStates.Visible : TreeStates.Hidden) + let { register, unregister } = useParentNesting() let prevShow = useRef(null) diff --git a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts index 3b76267f40..d2333ca77d 100644 --- a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts +++ b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts @@ -391,6 +391,57 @@ describe('Rendering', () => { expect(document.documentElement.style.overflow).toBe('hidden') }) ) + + it( + 'should wait to add a scroll lock to the html tag when unmount is false in a Transition', + suppressConsoleLogs(async () => { + renderTemplate({ + components: { + Dialog, + TransitionRoot, + }, + + template: ` +
+ + + + + + + + + +
+ `, + setup() { + let isOpen = ref(false) + return { + isOpen, + setIsOpen(value: boolean) { + isOpen.value = value + }, + toggleOpen() { + isOpen.value = !isOpen.value + }, + } + }, + }) + + // No overflow yet + expect(document.documentElement.style.overflow).toBe('') + + let btn = document.getElementById('trigger') + + // Open the dialog + await click(btn) + + // Expect overflow + expect(document.documentElement.style.overflow).toBe('hidden') + }) + ) }) describe('DialogOverlay', () => {