Skip to content

Commit

Permalink
feat: added focus trap to Popover... (#1164)
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh Goldberg authored Nov 18, 2020
1 parent b0e7c81 commit dd8958f
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ describe('Popover', () => {
isOpen: true,
onRequestClose,
});
fireEvent.keyDown(baseElement, { key: 'Escape', keyCode: 27 });
fireEvent.keyDown(baseElement, { key: 'escape', keyCode: 27 });
expect(onRequestClose).toBeCalledTimes(1);
});

Expand Down
59 changes: 27 additions & 32 deletions packages/gamut-labs/src/experimental/Popover/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import cx from 'classnames';
import FocusTrap from 'focus-trap-react';
import React, { useState, useCallback, useEffect, useRef } from 'react';
import { useWindowSize, useClickAway, useWindowScroll } from 'react-use';
import { useHotkeys } from 'react-hotkeys-hook';
import { useWindowSize, useWindowScroll } from 'react-use';

import styles from './styles.module.scss';
import { BodyPortal } from '@codecademy/gamut';
Expand Down Expand Up @@ -80,16 +80,6 @@ export const Popover: React.FC<PopoverProps> = ({
};
}, [targetRect, offset, align, position]);

const handleClickOutside = (event: MouseEvent | KeyboardEvent) => {
if (!isOpen) return;
if (
!targetRef?.current?.contains(event.target as Element) ||
event.type === 'keydown'
) {
onRequestClose?.();
}
};

useEffect(() => {
setTargetRect(targetRef?.current?.getBoundingClientRect());
}, [targetRef, isOpen, width, height, x, y]);
Expand All @@ -109,32 +99,37 @@ export const Popover: React.FC<PopoverProps> = ({
}, [targetRect, isInViewport, onRequestClose]);

const popoverRef = useRef<HTMLDivElement>(null);
useClickAway(popoverRef, handleClickOutside);
useHotkeys('escape', handleClickOutside, {}, [targetRect]);

if (!isOpen || !targetRef) return null;

return (
<BodyPortal>
<div
ref={popoverRef}
className={cx(
styles.popover,
styles[`${position}-${align}`],
outline && styles.outline,
className
)}
style={getPopoverPosition()}
data-testid="popover-content-container"
<FocusTrap
focusTrapOptions={{
clickOutsideDeactivates: true,
onDeactivate: onRequestClose,
}}
>
{showBeak && (
<div
className={cx(styles.beak, styles[`${position}-beak`])}
data-testid="popover-beak"
/>
)}
{children}
</div>
<div
ref={popoverRef}
className={cx(
styles.popover,
styles[`${position}-${align}`],
outline && styles.outline,
className
)}
style={getPopoverPosition()}
data-testid="popover-content-container"
>
{showBeak && (
<div
className={cx(styles.beak, styles[`${position}-beak`])}
data-testid="popover-beak"
/>
)}
{children}
</div>
</FocusTrap>
</BodyPortal>
);
};

0 comments on commit dd8958f

Please sign in to comment.