Commit Graph

8 Commits

Author SHA1 Message Date
Robin Malfait 0162c57d88 add React 18 compatibility (#1326)
* bump dev dependencies to React 18

* setup Jest to include `IS_REACT_ACT_ENVIRONMENT`

* prefer `useId` from React 18 if it exists

In React 16 & 17, where `useId` doesn't exist, we will fallback to our
implementation we have been using up until now.

The `useId` exposed by React 18, ensures stable references even in SSR
environments.

* update expected events

React 18 now uses the proper events:
- `blur` -> `focusout`
- `focus` -> `focusin`

* ensure to wait a bit longer

This is a bit unfortunate, but since React 18 now does an extra
unmount/remount in `StrictMode` to ensure that your code is
ConcurrentMode ready, it takes a bit longer to settle what the DOM sees.

That said, this is a temporary "hack". We are going to experiment with
using tools like Puppeteer/Playwright to run our tests in an actual
browser instead to eliminate all the weird details that we have to keep
in mind.

* prefer `.focus()` over `fireEvent.focus(el)`

* abstract `microTask` polyfill code

* prefer our `focus(el)` function over `el.focus()`

Internally we would still use `el.focus()`, but this allows us to have
more control over that `focus` function.

* add React 18 to the React Playground

* improve hooks for React 18

- Improving the cleanup of useEffect hooks
- useIsoMorphicEffect instead of normal useEffect, so that we can use
  useLayoutEffect to be a bit quicker.

* improve disposables

- This allows us to add event listeners on a node, and get automatic
  cleanup once `dispose` gets called.
- We also return all the `d.add` calls, so that we can cleanup specific
  parts only instead of everything or nothing.

* reimplement the Transition component to be React 18 ready

* wait an additional frame for everything to settle

* update playground examples

* suppressConsoleLogs for RadioGroup components

* update changelog

* keep the `to` classes for a smoother transition

In the next transition we will remove _all_ classes provided and re-add
the once we need.

---

Some extra special thanks:

- Thanks @silvenon for your initial work on the `transition` events in #926
- Thanks @thecrypticace for doing late-night debugging sessions

Co-authored-by: =?UTF-8?q?Matija=20Marohni=C4=87?= <matija.marohnic@gmail.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2022-04-13 22:07:01 +02:00
Robin Malfait c13e6b7752 Improve dialog and SSR (#477)
* delay initialization of Dialog

We were using a useLayoutEffect, now let's use a useEffect instead. It
still moves focus to the correct element, but that process is now a bit
delayed. This means that users will less-likely be urged to "hack"
around the issue by using fake focusable elements which will result in
worse accessibility.

* add hook to deal with server handoff

This will allow us to delay certain features. For example we can delay
the focus trapping until it is fully hydrated. We can also delay
rendering the Portal to ensure hydration works correctly.

* use server handoff complete hook

* update changelog
2021-05-04 12:18:53 +02:00
Robin Malfait ef00732685 cleanup and consistency (#213)
- Made the use of `const` and `let` consistent
- import required functions and types from 'react' instead of using the
  `React.` namespace.
- Added `Expand` type, which can expand complex types to their "final"
  result.
- Ensured that we use `as const` for DEFAULT_XXX_TAG where we used a
  string. So that we have the type of `div` instead of `string` for
  example.
- Used `interface` over `type` where possible. I'm personally more of a
  `type` fan. But the TypeScript recommends `interfaces` where possible
  because they are faster, yield better error messages and so on.
2021-01-30 14:46:54 +01:00
Robin Malfait b6212b9d44 ensure that we regenerate the id when it is still null 2021-01-29 12:23:10 +01:00
Robin Malfait 58ff88698b feat: add Listbox component (#3)
* make jest monorepo aware

* add @testing-library/jest-dom for custom matchers

This way we can use expect(element).toHaveAttribute(key, value?)

* abstract keys enum

* change type to unknown, because we don't know the return value

* update use-id hook, make it suspense aware

Thanks Reach UI!

* hoist the disposables collection

* add accessbility assertions for listbox

Also made it consistent for the Menu component and simplified some of the assertions

* add use-computed hook

This allows us re-render when hooks change, but also return a value. So this is a combination of useEffect and a useState value.

* add Listbox component

* bump dependencies

* add listbox example

* add lint-staged

This way we will only lint the files that have been staged and ready to be committed instead of the whole codebase

* add missing prevent defaults

* improve tests to verify that we can actually update the value of the listbox

* scroll the active listbox item into view

* small optimization, only focus "Nothing" on pointer leave when we are the active item

We used to always go to "Nothing" on pointer leave. And while this code
doesn't get called often, it *gets* called if you are using your arrow
keys and the mouse pointer is still over the list.

* bump dependencies

Also moved the tailwind dependencies to the root

* fix typo

* drop the default Transition inside the Menu and Listbox components

* update examples to reflect drop of default Transition wrapper

* rename Listbox.{Items,Item} to Listbox.{Options,Option}

Also rename all instances of `item` to `option` in tests and comments
and what have you...

* fix typo

* drop disabled prop, use aria-disabled only
2020-10-02 11:05:41 +02:00
Robin Malfait 93508e97a3 remove test code, use mocks instead 2020-09-18 14:05:22 +02:00
Robin Malfait 1b896b4992 add some dead code elimination markers 2020-09-17 23:24:40 +02:00
Robin Malfait 8b546f054b setup @headlessui/react package 2020-09-16 18:20:49 +02:00