From f91738f74a9bb1d65479449a05d628d28db16307 Mon Sep 17 00:00:00 2001 From: Andy Edwards Date: Wed, 28 Aug 2024 11:00:19 -0500 Subject: [PATCH] feat: default popupId to React.useId() if it exists (#137) * feat: default popupId to React.useId() if it exists fix #128 --- README.md | 18 ++++++++++++------ src/hooks.ts | 9 ++++++--- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6acc3c6..4440f4f 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ For MUI v4 you'll need `material-ui-popup-state@^1.9.3`. - [`usePopupState`](#usepopupstate) - [`usePopupState` Props](#usepopupstate-props) - [`variant` (`'popover'`, `'popper'`, or `'dialog'`, **required**)](#variant-popover-popper-or-dialog-required) - - [`popupId` (`string`, **optional** but strongly encouraged)](#popupid-string-optional-but-strongly-encouraged) + - [`popupId` (`string`, **optional**)](#popupid-string-optional) - [`disableAutoFocus` (`boolean`, **optional**)](#disableautofocus-boolean-optional) - [`usePopupState` return value](#usepopupstate-return-value) - [Examples with Render Props](#examples-with-render-props) @@ -49,7 +49,7 @@ For MUI v4 you'll need `material-ui-popup-state@^1.9.3`. - [Bind Functions](#bind-functions-1) - [`PopupState` Props](#popupstate-props) - [`variant` (`'popover'`, `'popper'`, or `'dialog'`, **required**)](#variant-popover-popper-or-dialog-required-1) - - [`popupId` (`string`, **optional** but strongly encouraged)](#popupid-string-optional-but-strongly-encouraged-1) + - [`popupId` (`string`, **optional**)](#popupid-string-optional) - [`disableAutoFocus` (`boolean`, **optional**)](#disableautofocus-boolean-optional-1) - [`children` (`(popupState: InjectedProps) => ?React.Node`, **required**)](#children-popupstate-injectedprops--reactnode-required) - [Using `Popover` and `Menu` with `bindHover`](#using-popover-and-menu-with-bindhover) @@ -278,14 +278,17 @@ popup is a `Popper`. Right now this only affects whether `bindTrigger`/`bindToggle`/`bindHover` return an `aria-controls` prop or an `aria-describedby` prop. -### `popupId` (`string`, **optional** but strongly encouraged) +### `popupId` (`string`, **optional**) The `id` for the popup component. It will be passed to the child props so that the trigger component may declare the same id in an ARIA prop. +Defaults to `React.useId()` if `React.useId` exists; in older versions of React +you will have to manually provide a `popupId`. + ### `disableAutoFocus` (`boolean`, **optional**) -If `true`, will not steal focus when the popup is opened. (And `bindPopover`/`bindMenu`) will inject `disableAutoFocus`, `disableEnforceFocus`, and `disableRestoreFocus`). +If `true`, will not steal focus when the popup is opened. (And `bindPopover`/`bindMenu` will inject `disableAutoFocus`, `disableEnforceFocus`, and `disableRestoreFocus`). Defaults to `true` when the popup is opened by the `bindHover` or `bindFocus` element. @@ -553,14 +556,17 @@ popup is a `Popper`. Right now this only affects whether `bindTrigger`/`bindToggle`/`bindHover` return an `aria-controls` prop or an `aria-describedby` prop. -### `popupId` (`string`, **optional** but strongly encouraged) +### `popupId` (`string`, **optional**) The `id` for the popup component. It will be passed to the child props so that the trigger component may declare the same id in an ARIA prop. +Defaults to `React.useId()` if `React.useId` exists; in older versions of React +you will have to manually provide a `popupId`. + ### `disableAutoFocus` (`boolean`, **optional**) -If `true`, will not steal focus when the popup is opened. (And `bindPopover`/`bindMenu`) will inject `disableAutoFocus`, `disableEnforceFocus`, and `disableRestoreFocus`). +If `true`, will not steal focus when the popup is opened. (And `bindPopover`/`bindMenu` will inject `disableAutoFocus`, `disableEnforceFocus`, and `disableRestoreFocus`). Defaults to `true` when the popup is opened by the `bindHover` or `bindFocus` element. diff --git a/src/hooks.ts b/src/hooks.ts index d6b898b..fa27c47 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -10,6 +10,7 @@ import { useRef, useEffect, } from 'react' +import * as React from 'react' import { type PopoverPosition, type PopoverReference } from '@mui/material' import { useEvent } from './useEvent' @@ -72,9 +73,11 @@ export const initCoreState: CoreState = { _deferNextClose: false, } +const defaultPopupId = 'useId' in React ? () => React.useId() : () => undefined + export function usePopupState({ parentPopupState, - popupId, + popupId = defaultPopupId(), variant, disableAutoFocus, }: { @@ -321,10 +324,10 @@ function controlAriaProps({ ...(variant === 'popover' ? { 'aria-haspopup': true, - 'aria-controls': isOpen && popupId != null ? popupId : undefined, + 'aria-controls': isOpen ? popupId : undefined, } : variant === 'popper' - ? { 'aria-describedby': isOpen && popupId != null ? popupId : undefined } + ? { 'aria-describedby': isOpen ? popupId : undefined } : undefined), } }