Commit Graph

318 Commits

Author SHA1 Message Date
Robin Malfait c0f0d43383 Reset form-like components when the parent <form> resets (#2004)
* add reset button to form example

* refactor React Listbox

This splitsup the raw `[state, dispatch]` to separate `useActions` and `useData` hooks.

This allows us to make the actions themselves simpler and include logic
that doesn't really belong in the reducer itself.

This also allows us to expose data via the `useData` hook that doesn't
belong in the state exposed from the `useReducer` hook.

E.g.: we used to store a `propsRef` from the root `Listbox`, and update
the ref with the new props in a `useEffect`. Now, we will just expose
that information directly via the `useData` hook. This simplifies the
code, removes useEffect's and so on.

* refactor Tabs, ensure function reference stays the same

If the `isControlled` value changes, then the references to all the
functions changed. Now they won't because of the `useEvent` hooks.

* type the actions abg similar to how we type the data bag

* refactor RadioGroup to use useData/useActions hooks

* reset Listbox to defaultValue on form reset

* reset Combobox to defaultValue on form reset

* reset RadioGroup to defaultValue on form reset

* reset Switch to defaultChecked on form reset

* port combinations/form playground example to Vue

* update changelog
2022-11-09 23:39:23 +01:00
Robin Malfait 74e7b43781 1.7.4 2022-11-03 16:21:15 +01:00
Robin Malfait f424aa20db Add client-only to mark everything as client components (#1981)
* add `client-only` to mark everything as client components

This should improve the error messages when using Headless UI in a
Next.js 13+ repo instead of getting a cryptic error message that
`createContext` doesn't exist.

* update changelog
2022-11-03 16:17:22 +01:00
Ernest dce2a1af07 fix: the order of compositionend events varies by browser (#1890)
* fix: the order of compositionend events varies by browser

* apply our style conventions

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2022-11-03 16:10:28 +01:00
Kristóf Poduszló f66f4926c4 fix(RadioGroup): defaultValue type definition (#1920) 2022-10-14 15:11:52 +02:00
Jordan Pittman ab78fbd91e Fire user’s onChange handler when we update the combobox input value internally (#1916)
* Fire user’s onChange handler when we update the input value internally

* Update changelog

* Fix CS
2022-10-10 15:17:52 -04:00
Robin Malfait 0e147a0c75 Fix useOutsideClick, add improvements for ShadowDOM (#1914)
* Fix `useOutsideClick` not closing when clicking in ShadowDOM

https://github.com/tailwindlabs/headlessui/pull/1876#issuecomment-1264742366

* use `getRootNode` in `useOutsideClick` for Vue

* update changelog

* run prettier

Co-authored-by: Theodore Messinezis <7229472+theomessin@users.noreply.github.com>
2022-10-10 17:02:51 +02:00
Jordan Pittman 1127a55a76 Warn when changing Combobox between controlled and uncontrolled (#1878) 2022-10-10 10:41:15 -04:00
Robin Malfait 83a5f456c3 Expose close function for Menu and Menu.Item components (#1897)
* expose `close` function for `Menu` and `Menu.Item` components

The `Menu` will already automatically close if you invoke the
`Menu.Item` (which is typically an `a` or a `button`). However you have
control over this, so if you add an explicit `onClick={e =>
e.preventDefault()}` then we respect that and don't execute the default
behavior, ergo closing the menu.

The problem occurs when you are using another component like the Inertia
`Link` component, that does have this `e.preventDefault()` built-in to
guarantee SPA-like page transitions without refreshing the browser.
Because of this, the menu will never close (unless you go to a totally
different page where the menu is not present of course).

This is where the explicit `close` function comes in, now you can use
that function to "force" close a menu, if your 3rd party tool already
bypassed the default behaviour.

This API is also how we do it in the `Popover` component for scenario's
where you can't rely on the default behaviour.

* update changelog
2022-10-04 15:49:20 +02:00
Robin Malfait af68a347fe Fix <Popover.Button as={Fragment} /> crash (#1889)
* prevent infinite loop

When you use `as={Fragment}` an unmount and remount can happen. This
means that the `ref` gets called with `null` for the unmount and
`HTMLButtonElement` for the mount.

This keeps toggling which results in an infinite loop and eventually a
Maximum callback size exceeded issue.

This ensures that we only set the button if we have a button.

* update changelog
2022-09-30 21:48:35 +02:00
Jordan Pittman fdccf0767a 1.7.3 2022-09-30 11:54:08 -04:00
Robin Malfait 9e9c08c7cc Fix Tab incorrectly activating on focus event (#1887)
* rework Tabs so that they don't change on focus

The "change on focus" was an incorrect implementation detail that made
it a bit easier but this causes a problem as seen in #1858.

If you want to conditionally check if you want to change the tab or note
(e.g. by using `window.confirm`) then the focus is lost while the popup
is shown. Regardless of your choice, the browser will re-focus the Tab
therefore asking you *again* what you want to do.

This fixes that by only activating the tab if needed while using arrow
keys or when you click the tab (not when it is focused).

* update changelog
2022-09-30 13:51:14 +02:00
Robin Malfait e7cfb05036 Fix useOutsideClick swallowing events inside ShadowDOM (#1886)
* check inside shadow dom for use-outside-click

* update changelog

Co-authored-by: Raphael Melloni <raphael.melloni@nortal.com>
2022-09-29 12:14:01 +02:00
Robin Malfait 8536838bb3 update changelog 2022-09-28 14:53:04 +02:00
Robin Malfait b032679ed0 Improve Portal detection for Popover components (#1842)
* improve Popover heuristics for detecting being inside a Portal

* improve performance of checks

* make it work in Vue

* verify behaviour in tests
2022-09-28 14:16:59 +02:00
Jordan Pittman 060f37b667 Fix use of undefined and displayValue in Combobox (#1865)
* Work around Vue multi-source + undefined bug

* Update changelog
2022-09-19 09:56:57 -04:00
Robin Malfait dd2feefb9e 1.7.2 2022-09-15 18:31:27 +02:00
Robin Malfait b346736659 Ensure we handle the static prop in Tab.Panel components correctly (#1856)
* ensure we handle `static` panels

* update changelog
2022-09-15 18:26:13 +02:00
Ernest e1f3ef862a Prevent option selection in ComboboxInput while composing (#1850)
* Fix should do nothing when event is fired within a composing session

* update changelog

* link to PR instead of issue

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2022-09-14 15:01:34 +02:00
Robin Malfait e926d693c5 1.7.1 2022-09-12 21:09:38 +02:00
Robin Malfait 1a145fdf43 Remove forceRerender from Tab component (#1846)
* remove `forceRerender` code

This was necessary to ensure the `Panel` and the `Tab` were properly
connected with eachother because it could happen that the `Tab` renders
but the corresponding `Panel` is not the active one which means that it
didn't have a DOM node and no `id` attached.

Whenever new `Tab` became active, it rerendered but the `Panel` wasn't
available yet, after that the `Panel` rendered and an `id` was available
but the actual `Tab` was already rendered so there was no link between
them.

We then forced a re-render because now the `Panel` does have a DOM node
ref attached and the `aria-labelledby` could be filled in.

However, in #1837 we fixed an issue where the order of `Tab` elements
with their corresponding `Panel` elements weren't always correct. To fix
this we ensured that the `Panel` always rendered a `<Hidden />`
component which means that a DOM node is always available.

This now means that we can get rid of the `forceRerender`.

* update changelog
2022-09-12 13:56:14 +02:00
Robin Malfait 46a7ab67ab Ensure Combobox.Label is properly linked when rendered after Combobox.Button and Combobox.Input components (#1838)
* ensure `Combbox.Label` is properly linked when rendered after other components

Even when rendered after the Combobox.Input / Combobox.Button

* update changelog
2022-09-08 23:18:33 +02:00
Robin Malfait b296b73783 Ensure Tab order stays consistent, and the currently active Tab stays active (#1837)
* ensure tabs order stays consistent

This ensures that whenever you insert or delete tabs before the current
tab, that the current tab stays active with the proper panel.

To do this we had to start rendering the non-visible panels as well, but
we used the `Hidden` component already which is position fixed and
completely hidden so this should not break layouts where using flexbox
or grid.

* update changelog

* fix TypeScript issue
2022-09-08 19:14:42 +02:00
Jordan Pittman 10f932afef Add <fieldset disabled> check to radio group options in React (#1835)
* wip

* Update changelog
2022-09-08 10:55:17 -04:00
Robin Malfait 397ba5c8c2 Improve iOS scroll locking (#1830)
* use a simpler `position: fixed` approach to prevent scroll locking

This isn't super ideal, but just preventing the default behavior on the
entire document while `touchmove`-ing isn't ideal either because then
you can't scroll inside the dialog or on the backdrop if your dialog
panel is larger than the viewport.

Again, this is not 100% correct, but it is better because you will be
able to scroll the dialog, and not the body.

* update changelog
2022-09-07 12:32:46 +02:00
Robin Malfait b93b7463bc 1.7.0 2022-09-06 16:22:42 +02:00
Jonathan Reinink dd8cfb427f Tweak changelogs 2022-09-06 10:15:13 -04:00
Robin Malfait 5667e84f35 Fix "blank" screen on initial load of Transition component (#1823)
* use a "cancellable" microTask

* update changelog
2022-09-06 13:37:55 +02:00
Robin Malfait 0954ec5243 Fix maximum call stack size exceeded error on Tab component when using as={Fragment} (#1826) 2022-09-06 12:35:24 +02:00
Robin Malfait df5b6a288c fix incorrect links in CHANGELOGs 2022-09-06 11:53:30 +02:00
Robin Malfait 25a4e7f721 Improve scroll lock on iOS (#1824)
* improve `Dialog` scroll lock on iOS

* add Dialog example to playground that's scrollable

* update changelog
2022-09-05 23:54:54 +02:00
Robin Malfait 1fd8cfcad0 Expose the value from the Combobox and Listbox components render prop (#1822)
* expose the `value` for `Combobox` and `Listbox`

* update changelog
2022-09-05 16:11:12 +02:00
Robin Malfait 3db54db1ba Fix ref stealing from children (#1820)
* fix ref stealing

When a higher-level component (like `Transition`) provides a `ref` to
its child component, then it will override the `ref` that was
potentially already on the child.

This will make sure that these are merged together correctly.

Fixes: #985

* update changelog
2022-09-05 13:09:23 +02:00
Jordan Pittman 13463f0295 Fix nullable by prop for combobox and radio group (#1815)
* Fix nullable by prop for combobox and radio group

* Update changelog
2022-09-02 16:10:10 -04:00
Jordan Pittman 5165be596f Allow the by prop (as a string) to handle null values (#1814)
* Allow the by prop (as a string) to handle null values

* Update changelog
2022-09-02 14:49:33 -04:00
Robin Malfait 4878092712 Improve accessibility when announcing Listbox.Option and Combobox.Option components (#1812)
* ensure that `aria-selected` is explicitly set to `false`

The WAI-ARIA Best Practices don't recommend this and prefer
`aria-selected: true` or undefined (aka not existing when it is
"false"). However in practice, both MacOS VoiceOver and NVDA experience
strange issues if you don't do this (e.g.: everything before the
selected item is also selected)

* update tests to ensure we are checking for `aria-selected=false`

* update changelog
2022-09-02 16:31:46 +02:00
Robin Malfait ed4d80e442 update changelog 2022-09-02 15:07:32 +02:00
Robin Malfait 0c0a15a6d8 Ensure enter transitions work when using unmount={false} (#1811)
* ensure we never start transitioning while the node is still hidden

* update changelog
2022-09-02 14:50:49 +02:00
Robin Malfait a98e55c34c Fix Transition component's incorrect cleanup and order of events (#1803)
* improve tracking of transitionableChildren

* remove weird outlier snapshots

If anything is still wrong the tests will still fail but the diffs will
be easier to read.

* remove event handling from `useTransition`

* handle before/after events in `Transition` directly

* fix incorrect logic bug in tests

* add very explicit test for transition event order

* ignore flakey tests for now

We will get back to these!

* ensure cancellation of transitions works properly

* update changelog
2022-09-02 00:44:52 +02:00
Jordan Pittman 920365c1b7 Stop scrolling when hitting end of focus trap (#1789)
* wip

* wip

* fix it

* fixit

* update changelog
2022-08-26 09:26:09 -04:00
Robin Malfait b301f04c77 Only restore focus to the Menu.Button if necessary when activating a Menu.Option (#1782)
* only restore focus to the Menu Button if necessary

This will check whether the focus got moved to somewhere else or not
once we activate an item via click or pressing `enter`.

Pressing escape will still move focus to the Menu Button.

* update changelog
2022-08-22 17:00:15 +02:00
Robin Malfait 486ac8075d Improve the types of the Combobox component (#1761)
* improve types of `Combobox`

Now given the `multiple` and/or `nullable` props we ensure that the
types for the `value`, `defaultValue`, `onChange`, `by`, render prop,
... are all correct.

You will also be able to easily tell which type to use instead of
inferring it by doing something like this:

```tsx
<Combobox<ExplicitTypeHere>
  value={...}
  onChange={...}
  ...
>
 ...
</Combobox>
```

* update changelog
2022-08-11 23:03:56 +02:00
Jordan Pittman b28d177a95 Fix displayValue syncing problem (#1755)
* ensure `syncInputValue` is updated correctly

* WIP

* WIP

* Don’t resync on open

* Fix react value syncing

update

* Add comment

* Port new setup over to Vue

* Remove `inputPropsRef`

We hardly knew ye

* Remove repro

* Cleanup

* Update changelog

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2022-08-10 12:38:30 -04:00
Robin Malfait 122eed7dbe Only select the active option when using "singular" mode (#1750)
* only select the active option when using "singular" mode

* update changelog
2022-08-09 16:38:29 +02:00
Robin Malfait 4c433cdf5c Ensure Disclosure.Panel is properly linked (#1747)
* ensure `Disclosure.Panel` is properly linked

* update changelog
2022-08-09 13:38:15 +02:00
Markus Baumer fa10cb0fb9 fixes tailwindlabs/headlessui#1733 (#1734) 2022-08-03 21:16:49 +02:00
Eddy Sims db736d8c37 Allow MouseEventHandler types to passed close from Popovers (#1696)
* fix: adds the MouseEventHandler type to close

* WIP

* WIP

* Update changelog

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2022-08-02 16:01:27 -04:00
Robin Malfait 4d88dd9d7e Improve Combobox re-opening keyboard issue on mobile (#1732)
* prevent re-focusing Combobox Input after choosing selection

On mobile this gives a bit of annoying results where after choosing an
option, the keyboard is shown again because the input is focused again.

* update changelog
2022-08-01 15:27:39 +02:00
Robin Malfait cbb4f19fb3 update changelog 2022-08-01 12:38:49 +02:00
Robin Malfait 1831832458 Make form components uncontrollable (#1683)
* implement uncontrolled form components

A few versions ago we introduced compatibility with the native `form`
element. This means that behind the scenes we render hidden inputs that
are kept in sync which allows you to submit your normal form and get
data via `new FormData(event.currentTarget)`.

Before this change every form related component (Switch, RadioGroup,
Listbox and Combobox) always had to be passed a `value` and an
`onChange` regardless of this change.

This change will allow you to not even use the `value` and the
`onChange` at all and keep it completely uncontrolled.

This has some changes:

- `value` is made optional
- `onChange` is made optional (but will still be called if passed
  regardless of being controlled or uncontrolled)
- `defaultValue` got added so that you can still pre-fill your values
  with known values.
- `value` render prop got exposed so that you can still use this while
  rendering.

This should also make it completely compatible with tools like Remix
without wiring up your own state.

* update example combinations/form playground to use uncontrolled
components

* improve types, add missing render prop arguments

* add tests for uncontrolled components (React)

* implement uncontrolled form elements in Vue
2022-08-01 12:37:50 +02:00