Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement sibling
<Dialog />
components (#3242)
* add `DefaultMap` implementation * add `useHierarchy` hook * start `FocusTrapFeatures.None` with `0` instead of `1` * simplify `Dialog`'s implementation By making use of the new `useHierarchy` hook. * delete `StackContext` and `StackProvider` components They are now replaced by the new `useHierarchy` hook. * use `useHierarchy` in `useOutsideClick` hook This way we can scope the hierarchy inside of the `useOutsideClick` hook. This now ensures that we only enable the `useOutsideClick` on the top-most element (the one that last enabled it). * use `useHierarchy` in `useInertOthers` hook * add new `useEscape` hook * use new `useEscape` hook * use `useHierarchy` in `useEscape` hook * use `useHierarchy` in `useScrollLock` hook * pass features instead of `enabled` boolean * simplify demo mode feature flags No need to setup focus feature flags and then disable it all again if demo mode is enabled. * use similar signature for hooks with `enabled` parameter Whenever a hook requires an `enabled` state, the `enabled` parameter is moved to the front. Initially this was the last argument and enabled by default but everywhere we use these hooks we have to pass a dedicated boolean anyway. This makes sure these hooks follow a similar pattern. Bonus points because Prettier can now improve formatting the usage of these hooks. The reason why is because there is no additional argument after the potential last callback. Before: ```ts let enabled = data.__demoMode ? false : modal && data.comboboxState === ComboboxState.Open useInertOthers( { allowed: useEvent(() => [ data.inputRef.current, data.buttonRef.current, data.optionsRef.current, ]), }, enabled ) ``` After: ```ts let enabled = data.__demoMode ? false : modal && data.comboboxState === ComboboxState.Open useInertOthers(enabled, { allowed: useEvent(() => [ data.inputRef.current, data.buttonRef.current, data.optionsRef.current, ]), }) ``` * move `focusTrapFeatures` parameter to the front * drop `FocusTrapFeatures.All`, list them explicitly The `All` feature didn't include all feature flags (didn't include `FocusTrapFeatures.AutoFocus` for example). * always enable `FocusTrapFeatures.RestoreFocus` when enabled This way we can get rid of the `Position.HasChild` check, which will allow us to do more cleanup soon in the `useHierarchy` hook. * use `useHierarchy` in `<FocusTrap>` component * drop `useHierarchy` from `<Dialog>` component * simplify focusTrapFeatures setup * simplify `useHierarchy` The `useHierarchy` hook allowed us to determine whether we are in the root, in the middle, a leaf, have a parent, have a child, ... but we only ever checked whether we are a leaf node or not. In other words, you can think of it like "are we the top layer" This simplifies the implementation and usage of this new hook. * move `enabled`-like argument to front Just to be consistent with the other hooks. * polyfill `toSpliced` for older Node versions * add sibling dialogs playground * rename `useHierarchy` to `useIsTopLayer` * inline variable * remove `unstable_batchedUpdates` This is not necessary. * add tiny bit of information to dialog Because it might not be super obvious that we are going to close the `<Dialog />`. * update changelog * re-add internal `PortalGroup` This is necessary to make sure that a component like a `<MenuItems anchor />` is rendered inside of the `<Dialog />` and not as a sibling. While this all works from a functional perspective, if you rely on a CSS variable that was defined on the `<Dialog />` and you use it in the `<MenuItems />` then without this change it wouldn't work.
- Loading branch information