Skip to content

Commit

Permalink
Merge pull request #404 from masakudamatsu/refactor-popups
Browse files Browse the repository at this point in the history
Animate the closing of popups
  • Loading branch information
masakudamatsu authored Jan 16, 2023
2 parents 34b9469 + a3fb6e2 commit afd51d8
Show file tree
Hide file tree
Showing 38 changed files with 1,849 additions and 619 deletions.
3 changes: 2 additions & 1 deletion jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"compilerOptions": {
"baseUrl": "."
"baseUrl": ".",
"target": "esnext"
}
}
53 changes: 32 additions & 21 deletions src/components/CloseButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,56 @@ import {forwardRef, useImperativeHandle, useRef} from 'react';
import PropTypes from 'prop-types';

import {ButtonCircle} from 'src/elements/ButtonCircle';
import {createRipple} from 'src/utils/createRipple';

// TODO #201:
// 2. Reuse this component in MenuButton
export const CloseButton = forwardRef(function CloseButton(
{
ariaControls = null,
ariaExpanded = null,
ariaLabel,
handleClick,
testId = null,
},
{ariaExpanded = null, ariaLabel, handleClick, testId = null},
ref,
) {
const buttonElement = useRef();
const focusButton = () => buttonElement.current.focus();
useImperativeHandle(ref, () => ({focusButton}));
const clickHandler = event => {
createRipple(event);
handleClick();
};
const keydownHandler = event => {
if (event.key === 'Enter') {
event.preventDefault(); // otherwise click event will be fired as well
createRipple(event);
handleClick();
// Handle the clicking with Enter key
if (event.clientX === 0 && event.clientY === 0) {
const {
height: buttonHeight,
left: buttonPositionLeft,
top: buttonPositionTop,
width: buttonWidth,
} = event.currentTarget.getBoundingClientRect();
event.clientX = buttonPositionLeft + buttonWidth / 2;
event.clientY = buttonPositionTop + buttonHeight / 2;
}
// Obtain the size and position of the ripple
const popup = event.currentTarget.offsetParent; // event.target would refer to <svg>, not <button>
const {
left: popupLeft,
top: popupTop,
height: popupHeight,
width: popupWidth,
} = popup.getBoundingClientRect();
const popupDiagonalLength = Math.sqrt(
Math.pow(popupWidth, 2) + Math.pow(popupHeight, 2),
);
const rippleRadius = popupDiagonalLength;
const rippleCenter = {
x: event.clientX - popupLeft,
y: event.clientY - popupTop,
};
handleClick({
rippleDiameter: `${Math.round(rippleRadius * 2)}px`,
ripplePositionLeft: `${Math.round(rippleCenter.x - rippleRadius)}px`,
ripplePositionTop: `${Math.round(rippleCenter.y - rippleRadius)}px`,
});
};

return (
<>
<ButtonCircle
aria-controls={ariaControls}
aria-expanded={ariaExpanded}
aria-label={ariaLabel}
data-testid={testId}
onClick={clickHandler}
onKeyDown={keydownHandler}
ref={buttonElement}
type="button"
>
Expand All @@ -53,7 +65,6 @@ export const CloseButton = forwardRef(function CloseButton(
});

CloseButton.propTypes = {
ariaControls: PropTypes.string,
ariaExpanded: PropTypes.string,
ariaLabel: PropTypes.string.isRequired,
handleClick: PropTypes.func.isRequired,
Expand Down
14 changes: 8 additions & 6 deletions src/components/CloseButton.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import userEvent from '@testing-library/user-event';
import {axe} from 'jest-axe';

import {CloseButton} from './CloseButton';
import {createRipple as mockCreateRipple} from 'src/utils/createRipple';

jest.mock('src/utils/createRipple');

beforeEach(() => {
jest.clearAllMocks();
Expand All @@ -17,6 +14,14 @@ const mockProps = {
handleClick: jest.fn().mockName('handleClick'),
};

// Mock offsetParent
// source: https://github.com/jsdom/jsdom/issues/1261#issuecomment-362928131
Object.defineProperty(HTMLElement.prototype, 'offsetParent', {
get() {
return this.parentNode;
},
});

describe(`Clicking the button`, () => {
beforeEach(() => {
render(<CloseButton {...mockProps} />);
Expand All @@ -25,9 +30,6 @@ describe(`Clicking the button`, () => {
test(`calls a function specified with handleClick prop`, () => {
expect(mockProps.handleClick).toHaveBeenCalledTimes(1);
});
test(`calls createRipple()`, () => {
expect(mockCreateRipple).toHaveBeenCalledTimes(1);
});
});

test('Accessibility checks', async () => {
Expand Down
Loading

1 comment on commit afd51d8

@vercel
Copy link

@vercel vercel bot commented on afd51d8 Jan 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.