From 556afbda728ef34a278f786f11cce6c459817178 Mon Sep 17 00:00:00 2001 From: Dustin Savery <2447456+dusave@users.noreply.github.com> Date: Tue, 19 Nov 2024 09:49:44 -0800 Subject: [PATCH] Fix HMR errors (#5209) * adding optional chaining checks to aid with hot-module reloading * Add changeset --------- Co-authored-by: Cameron Dutro --- .changeset/tidy-turtles-protect.md | 5 ++++ packages/react/src/ActionMenu/ActionMenu.tsx | 4 ++- .../react/src/hooks/useMenuInitialFocus.ts | 10 +++---- .../src/hooks/useMenuKeyboardNavigation.ts | 26 +++++++++---------- 4 files changed, 26 insertions(+), 19 deletions(-) create mode 100644 .changeset/tidy-turtles-protect.md diff --git a/.changeset/tidy-turtles-protect.md b/.changeset/tidy-turtles-protect.md new file mode 100644 index 00000000000..6d378fe75da --- /dev/null +++ b/.changeset/tidy-turtles-protect.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +Check certain refs for nullishness to address HMR issues in dotcom diff --git a/packages/react/src/ActionMenu/ActionMenu.tsx b/packages/react/src/ActionMenu/ActionMenu.tsx index 376dce0ac1a..b2dd4b81a9b 100644 --- a/packages/react/src/ActionMenu/ActionMenu.tsx +++ b/packages/react/src/ActionMenu/ActionMenu.tsx @@ -260,7 +260,9 @@ const Overlay: React.FC> = ({ // If the menu anchor is an icon button, we need to label the menu by tooltip that also labelled the anchor. const [anchorAriaLabelledby, setAnchorAriaLabelledby] = useState(null) useEffect(() => { - if (anchorRef.current) { + // Necessary for HMR reloads + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (anchorRef?.current) { const ariaLabelledby = anchorRef.current.getAttribute('aria-labelledby') if (ariaLabelledby) { setAnchorAriaLabelledby(ariaLabelledby) diff --git a/packages/react/src/hooks/useMenuInitialFocus.ts b/packages/react/src/hooks/useMenuInitialFocus.ts index 103dccb89c0..3897796d8a0 100644 --- a/packages/react/src/hooks/useMenuInitialFocus.ts +++ b/packages/react/src/hooks/useMenuInitialFocus.ts @@ -3,8 +3,8 @@ import {iterateFocusableElements} from '@primer/behaviors/utils' export const useMenuInitialFocus = ( open: boolean, - containerRef: React.RefObject, - anchorRef: React.RefObject, + containerRef?: React.RefObject, + anchorRef?: React.RefObject, ) => { /** * We need to pick the first element to focus based on how the menu was opened, @@ -15,7 +15,7 @@ export const useMenuInitialFocus = ( React.useEffect( function inferOpeningKey() { - const anchorElement = anchorRef.current + const anchorElement = anchorRef?.current const clickHandler = (event: MouseEvent) => { // event.detail === 0 means onClick was fired by Enter/Space key @@ -46,12 +46,12 @@ export const useMenuInitialFocus = ( */ React.useEffect( function moveFocusOnOpen() { - if (!open || !containerRef.current) return // wait till the menu is open + if (!open || !containerRef?.current) return // wait till the menu is open const iterable = iterateFocusableElements(containerRef.current) if (openingGesture === 'mouse-click') { - if (anchorRef.current) anchorRef.current.focus() + if (anchorRef?.current) anchorRef.current.focus() else throw new Error('For focus management, please attach anchorRef') } else if (openingGesture && ['ArrowDown', 'Space', 'Enter'].includes(openingGesture)) { const firstElement = iterable.next().value diff --git a/packages/react/src/hooks/useMenuKeyboardNavigation.ts b/packages/react/src/hooks/useMenuKeyboardNavigation.ts index 4000fd578fe..96150189354 100644 --- a/packages/react/src/hooks/useMenuKeyboardNavigation.ts +++ b/packages/react/src/hooks/useMenuKeyboardNavigation.ts @@ -14,9 +14,9 @@ import type {MenuCloseHandler} from '../ActionMenu' export const useMenuKeyboardNavigation = ( open: boolean, onClose: MenuCloseHandler | undefined, - containerRef: React.RefObject, - anchorRef: React.RefObject, - isSubmenu: boolean, + containerRef?: React.RefObject, + anchorRef?: React.RefObject, + isSubmenu: boolean = false, ) => { useMenuInitialFocus(open, containerRef, anchorRef) useMnemonics(open, containerRef) @@ -32,12 +32,12 @@ export const useMenuKeyboardNavigation = ( const useCloseMenuOnTab = ( open: boolean, onClose: MenuCloseHandler | undefined, - containerRef: React.RefObject, - anchorRef: React.RefObject, + containerRef?: React.RefObject, + anchorRef?: React.RefObject, ) => { React.useEffect(() => { - const container = containerRef.current - const anchor = anchorRef.current + const container = containerRef?.current + const anchor = anchorRef?.current const handler = (event: KeyboardEvent) => { if (open && event.key === 'Tab') onClose?.('tab') @@ -59,10 +59,10 @@ const useCloseSubmenuOnArrow = ( open: boolean, isSubmenu: boolean, onClose: MenuCloseHandler | undefined, - containerRef: React.RefObject, + containerRef?: React.RefObject, ) => { React.useEffect(() => { - const container = containerRef.current + const container = containerRef?.current const handler = (event: KeyboardEvent) => { if (open && isSubmenu && event.key === 'ArrowLeft') onClose?.('arrow-left') @@ -81,12 +81,12 @@ const useCloseSubmenuOnArrow = ( */ const useMoveFocusToMenuItem = ( open: boolean, - containerRef: React.RefObject, - anchorRef: React.RefObject, + containerRef?: React.RefObject, + anchorRef?: React.RefObject, ) => { React.useEffect(() => { - const container = containerRef.current - const anchor = anchorRef.current + const container = containerRef?.current + const anchor = anchorRef?.current const handler = (event: KeyboardEvent) => { if (!open || !container) return