Skip to content

Commit

Permalink
Fix useCollapsible not closing immediately (#1169)
Browse files Browse the repository at this point in the history
  • Loading branch information
connor-baer authored Sep 15, 2021
1 parent b1a6b37 commit 0c7416c
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/proud-apples-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sumup/circuit-ui': minor
---

Exposed the `isAnimating` state from the useCollapsible hook.
5 changes: 5 additions & 0 deletions .changeset/warm-meals-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sumup/circuit-ui': patch
---

Fixed a bug in the `useCollapsible` hook to start the closing animation immediately.
14 changes: 9 additions & 5 deletions packages/circuit-ui/hooks/useCollapsible/useCollapsible.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import { MouseEvent } from 'react';

import { renderHook, actHook } from '../../util/test-utils';
import { renderHook, actHook, waitFor } from '../../util/test-utils';

import { useCollapsible, getHeight } from './useCollapsible';

Expand Down Expand Up @@ -158,7 +158,7 @@ describe('useCollapsible', () => {
});

describe('toggling', () => {
it('should toggle the open state when the button is clicked', () => {
it('should toggle the open state when the button is clicked', async () => {
const event = ({ fizz: 'buzz' } as unknown) as MouseEvent;
const { result } = renderHook(() => useCollapsible());
const { getButtonProps } = result.current;
Expand All @@ -169,10 +169,12 @@ describe('useCollapsible', () => {
getButtonProps().onClick(event);
});

expect(result.current.isOpen).toBeTruthy();
await waitFor(() => {
expect(result.current.isOpen).toBeTruthy();
});
});

it('should toggle the open state when the callback is called', () => {
it('should toggle the open state when the callback is called', async () => {
const { result } = renderHook(() => useCollapsible());

expect(result.current.isOpen).toBeFalsy();
Expand All @@ -181,7 +183,9 @@ describe('useCollapsible', () => {
result.current.toggleOpen();
});

expect(result.current.isOpen).toBeTruthy();
await waitFor(() => {
expect(result.current.isOpen).toBeTruthy();
});
});
});

Expand Down
17 changes: 9 additions & 8 deletions packages/circuit-ui/hooks/useCollapsible/useCollapsible.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type ContentProps<T> = {
type Collapsible<T> = {
isOpen: boolean;
toggleOpen: () => void;
isAnimating: boolean;
getButtonProps: (props?: {
onClick?: (event: ClickEvent) => void;
}) => ButtonProps;
Expand All @@ -69,29 +70,29 @@ export function useCollapsible<T extends HTMLElement = HTMLElement>({
const contentElement = useRef<T>(null);
const [isOpen, setOpen] = useState(initialOpen);
const [height, setHeight] = useState(getHeight(contentElement));
const [, setAnimating] = useAnimation();
const [isAnimating, setAnimating] = useAnimation();

const toggleOpen = useCallback(() => {
setAnimating({
duration,
onStart: () => {
setHeight(getHeight(contentElement));
if (!isOpen) {
setOpen(true);
}
// Delaying the state update until the next animation frame ensures that
// the browsers renders the new height before the animation starts.
window.requestAnimationFrame(() => {
setOpen((prev) => !prev);
});
},
onEnd: () => {
if (isOpen) {
setOpen(false);
}
setHeight(DEFAULT_HEIGHT);
},
});
}, [isOpen, setAnimating, duration]);
}, [setAnimating, duration]);

return {
isOpen,
toggleOpen,
isAnimating,
getButtonProps: (props = {}) => ({
'onClick': (event: ClickEvent) => {
if (props.onClick) {
Expand Down

0 comments on commit 0c7416c

Please sign in to comment.