Skip to content

Commit

Permalink
Fix hanging tests when using anchor prop (#3357)
Browse files Browse the repository at this point in the history
* add test that verifies unit test hang

* bail when parsing the `maxHeight` results in `NaN`

* playground cleanup

Testing using this playground example, so cleaned it up to be more
modern using newer components, transition prop and so on.

* use CSS instead of JS

Let's make it a CSS problem instead of a JS problem. The
`round(up, <valueToRound>, <roundingInterval>)` will behave similar to a
`Math.ceil()` that we had in the JS implementation.

See: https://developer.mozilla.org/en-US/docs/Web/CSS/round

* Remove CSS solution for now

I want to re-enable this in the future, but unfortunately for now we
can't use it because Chrome only introduced support for this in the last
2 months.

This reverts commit daac60d45ec3f02b324d0d8b18078a995e885733.

* update changelog
  • Loading branch information
RobinMalfait committed Jul 3, 2024
1 parent d65829b commit 70f88f4
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 48 deletions.
1 change: 1 addition & 0 deletions packages/@headlessui-react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix prematurely added anchoring styles on `ListboxOptions` ([#3337](https://github.com/tailwindlabs/headlessui/pull/3337))
- Ensure `unmount` on `Dialog` works in combination with the `transition` prop on `DialogBackdrop` and `DialogPanel` components ([#3352](https://github.com/tailwindlabs/headlessui/pull/3352))
- Fix crash in `Combobox` component when in `virtual` mode when options are empty ([#3356](https://github.com/tailwindlabs/headlessui/pull/3356))
- Fix hanging tests when using `anchor` prop ([#3357](https://github.com/tailwindlabs/headlessui/pull/3357))

## [2.1.1] - 2024-06-26

Expand Down
20 changes: 20 additions & 0 deletions packages/@headlessui-react/src/components/popover/popover.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,26 @@ describe('Rendering', () => {
assertActiveElement(getByText('restorable'))
})
)

it(
'should be possible to use the `anchor` prop on the `PopoverPanel`',
suppressConsoleLogs(async () => {
render(
<Popover>
<PopoverButton>Trigger</PopoverButton>
<PopoverPanel anchor="bottom">Panel open</PopoverPanel>
</Popover>
)

assertPopoverButton({ state: PopoverState.InvisibleUnmounted })
assertPopoverPanel({ state: PopoverState.InvisibleUnmounted })

await click(getPopoverButton())

assertPopoverButton({ state: PopoverState.Visible })
assertPopoverPanel({ state: PopoverState.Visible })
})
)
})

describe('Multiple `Popover.Button` warnings', () => {
Expand Down
13 changes: 10 additions & 3 deletions packages/@headlessui-react/src/internal/floating.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -375,9 +375,16 @@ function useFixScrollingPixel(element: HTMLElement | null) {
if (!element) return

let observer = new MutationObserver(() => {
let maxHeight = element.style.maxHeight
if (parseFloat(maxHeight) !== parseInt(maxHeight)) {
element.style.maxHeight = `${Math.ceil(parseFloat(maxHeight))}px`
let maxHeight = window.getComputedStyle(element).maxHeight

let maxHeightFloat = parseFloat(maxHeight)
if (isNaN(maxHeightFloat)) return

let maxHeightInt = parseInt(maxHeight)
if (isNaN(maxHeightInt)) return

if (maxHeightFloat !== maxHeightInt) {
element.style.maxHeight = `${Math.ceil(maxHeightFloat)}px`
}
})

Expand Down
75 changes: 30 additions & 45 deletions playgrounds/react/pages/listbox/listbox-with-pure-tailwind.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Listbox, Transition } from '@headlessui/react'
import { Label, Listbox, ListboxButton, ListboxOption, ListboxOptions } from '@headlessui/react'
import { useEffect, useState } from 'react'

let people = [
Expand Down Expand Up @@ -26,20 +26,12 @@ export default function Home() {
<div className="flex h-full w-screen justify-center bg-gray-50 p-12">
<div className="mx-auto w-full max-w-xs">
<div className="space-y-1">
<Listbox
value={active}
onChange={(value) => {
console.log('value:', value)
setActivePerson(value)
}}
>
<Listbox.Label className="block text-sm font-medium leading-5 text-gray-700">
Assigned to
</Listbox.Label>
<Listbox value={active} onChange={setActivePerson}>
<Label className="block text-sm font-medium leading-5 text-gray-700">Assigned to</Label>

<div className="relative">
<span className="inline-block w-full rounded-md shadow-sm">
<Listbox.Button className="focus:shadow-outline-blue relative w-full cursor-default rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 text-left transition duration-150 ease-in-out focus:border-blue-300 focus:outline-none sm:text-sm sm:leading-5">
<ListboxButton className="relative w-full cursor-default rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 text-left transition duration-150 ease-in-out sm:text-sm sm:leading-5">
<span className="block truncate">{active}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<svg
Expand All @@ -56,42 +48,35 @@ export default function Home() {
/>
</svg>
</span>
</Listbox.Button>
</ListboxButton>
</span>

<Transition
enter="transition duration-500 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-500 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
<ListboxOptions
anchor="bottom"
transition
className="w-[var(--button-width)] overflow-auto rounded-md border border-gray-300 bg-white py-1 text-base leading-6 shadow-lg transition duration-200 ease-out [--anchor-gap:theme(spacing.1)] [--anchor-max-height:theme(spacing.60)] focus:outline-none data-[closed]:scale-95 data-[closed]:opacity-0 sm:text-sm sm:leading-5"
>
<div className="absolute mt-1 w-full rounded-md bg-white shadow-lg">
<Listbox.Options className="shadow-xs max-h-60 overflow-auto rounded-md py-1 text-base leading-6 focus:outline-none sm:text-sm sm:leading-5">
{people.map((name) => (
<Listbox.Option
key={name}
value={name}
className="group relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900 focus:outline-none data-[active]:bg-indigo-600 data-[active]:text-white"
>
<span className="block truncate font-normal group-data-[selected]:font-semibold">
{name}
</span>
<span className="absolute inset-y-0 right-0 hidden items-center pr-4 text-indigo-600 group-data-[selected]:flex group-data-[active]:text-white">
<svg className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clipRule="evenodd"
/>
</svg>
</span>
</Listbox.Option>
))}
</Listbox.Options>
</div>
</Transition>
{people.map((name) => (
<ListboxOption
key={name}
value={name}
className="group relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900 focus:outline-none data-[active]:bg-indigo-600 data-[active]:text-white"
>
<span className="block truncate font-normal group-data-[selected]:font-semibold">
{name}
</span>
<span className="absolute inset-y-0 right-0 hidden items-center pr-4 text-indigo-600 group-data-[selected]:flex group-data-[active]:text-white">
<svg className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clipRule="evenodd"
/>
</svg>
</span>
</ListboxOption>
))}
</ListboxOptions>
</div>
</Listbox>
</div>
Expand Down

0 comments on commit 70f88f4

Please sign in to comment.