Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
portal
prop to Combobox
, Listbox
, Menu
and Popover
comp…
…onents (#3124) * move duplicated `useScrollLock` to dedicated hook * accept `enabled` prop on `Portal` component This way we can always use `<Portal>`, but enable / disable it conditionally. * use `useSyncRefs` in portal This allows us to _not_ provide the ref is no ref was passed in. * refactor inner workings of `useInert` moved logic from the `useEffect`, to module scope. We will re-use this logic in a future commit. * add `useInertOthers` hook Mark all elements on the page as inert, except for the ones that are allowed. We move up the tree from the allowed elements, and mark all their siblings as `inert`. If any of the children happens to be a parent of one of the elements, then that child will not be marked as `inert`. ``` <body> <!-- Stop at body --> <header></header> <!-- Inert, sibling of parent of allowed element --> <main> <!-- Not inert, parent of allowed element --> <div>Sidebar</div> <!-- Inert, sibling of parent of allowed element --> <div> <!-- Not inert, parent of allowed element --> <Listbox> <!-- Not inert, parent of allowed element --> <ListboxButton></ListboxButton> <!-- Not inert, allowed element --> <ListboxOptions></ListboxOptions> <!-- Not inert, allowed element --> </Listbox> </div> </main> <footer></footer> <!-- Inert, sibling of parent of allowed element --> </body> ``` * add `portal` prop, and change meaning of `modal` prop on `MenuItems` - This adds a `portal` prop that renders the `MenuItems` in a portal. Defaults to `false`. - If you pass an `anchor` prop, the `portal` prop will always be set to `true`. - The `modal` prop enables the following behavior: - Scroll locking is enabled when the `modal` prop is passed and the `Menu` is open. - Other elements but the `Menu` are marked as `inert`. * add `portal` prop, and change meaning of `modal` prop on `ListboxOptions` - This adds a `portal` prop that renders the `ListboxOptions` in a portal. Defaults to `false`. - If you pass an `anchor` prop, the `portal` prop will always be set to `true`. - The `modal` prop enables the following behavior: - Scroll locking is enabled when the `modal` prop is passed and the `Listbox` is open. - Other elements but the `Listbox` are marked as `inert`. * add `portal` and `modal` prop on `ComboboxOptions` - This adds a `portal` prop that renders the `ComboboxOptions` in a portal. Defaults to `false`. - If you pass an `anchor` prop, the `portal` prop will always be set to `true`. - The `modal` prop enables the following behavior: - Scroll locking is enabled when the `modal` prop is passed and the `Combobox` is open. - Other elements but the `Combobox` are marked as `inert`. * add `portal` prop, and change meaning of `modal` prop on `PopoverPanel` - This adds a `portal` prop that renders the `PopoverPanel` in a portal. Defaults to `false`. - If you pass an `anchor` prop, the `portal` prop will always be set to `true`. - The `modal` prop enables the following behavior: - Scroll locking is enabled when the `modal` prop is passed and the `Panel` is open. * simplify popover playground, use provided `anchor` prop * remove internal `Modal` component This is now implemented on a per component basis with some hooks. * remove `Modal` handling from `Dialog` The `Modal` component is removed, so there is no need to handle this in the `Dialog`. It's also safe to remove because the components with "portals" that are rendered inside the `Dialog` are portalled into the `Dialog` and not as a sibling of the `Dialog`. * ensure we use `groupTarget` if it is already available Before this, we were waiting for a "next render" to mount the portal if it was used inside a specific group. This happens when using `<Portal/>` inside of a `<Dialog/>`. * update changelog * add tests for `useInertOthers` * ensure we stop before the `body` We used to have a `useInertOthers` hook, but it also made everything inside `document.body` inert. This means that third party packages or browser extensions that inject something in the `document.body` were also marked as `inert`. This is something we don't want. We fixed that previously by introducing a simpler `useInert` where we explicitly marked certain elements as inert: #2290 But I believe this new implementation is better, especially with this commit where we stop once we hit `document.body`. This means that we will never mark `body > *` elements as `inert`. * add `allowed` and `disallowed` to `useInertOthers` This way we have a list of allowed and disallowed containers. The `disallowed` elements will be marked as inert as-is. The allowed elements will not be marked as `inert`, but it will mark its children as inert. Then goes op the parent tree and repeats the process. * simplify `useInertOthers` in `Dialog` code * update `use-inert` tests to always use `useInertOthers` * remove `useInert` hook in favor of `useInertOthers` * rename `use-inert` to `use-inert-others` * cleanup default values for `useInertOthers`
- Loading branch information