From 2b906d1044cba6c27804da9b6250901429c5cb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=B8egh?= Date: Mon, 3 Oct 2022 14:28:43 +0200 Subject: [PATCH] feat(HeightAnimation): add onInit to get animation instance --- .../components/height-animation/events.md | 9 +-- .../height-animation/HeightAnimation.tsx | 2 + .../__tests__/HeightAnimation.test.tsx | 70 +++++++++++++++++++ .../height-animation/useHeightAnimation.tsx | 14 +++- 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/height-animation/events.md b/packages/dnb-design-system-portal/src/docs/uilib/components/height-animation/events.md index 21cdb369a28..0bfb6c2878b 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/height-animation/events.md +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/height-animation/events.md @@ -4,7 +4,8 @@ showTabs: true ## Events -| Events | Description | -| -------- | ----------------------------------------------------------------------------------------------------- | -| `onOpen` | _(optional)_ Is called when fully opened or closed. Returns `true` or `false` depending on the state. | -| `onOpen` | _(optional)_ Is called when fully opened or closed. Returns `true` or `false` depending on the state. | +| Events | Description | +| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `onOpen` | _(optional)_ Is called when fully opened or closed. Returns `true` or `false` depending on the state. | +| `onAnimationEnd` | _(optional)_ Is called when aanimation is done and the full height has been reached.. | +| `onInit` | _(optional)_ Is called once before mounting the component (useLayoutEffect). Returns the instance of the internal animation class. | diff --git a/packages/dnb-eufemia/src/components/height-animation/HeightAnimation.tsx b/packages/dnb-eufemia/src/components/height-animation/HeightAnimation.tsx index 8b7a57b5c54..568865f1247 100644 --- a/packages/dnb-eufemia/src/components/height-animation/HeightAnimation.tsx +++ b/packages/dnb-eufemia/src/components/height-animation/HeightAnimation.tsx @@ -44,6 +44,7 @@ export default function HeightAnimation({ className, innerRef, children, + onInit = null, onOpen = null, onAnimationEnd = null, ...props @@ -55,6 +56,7 @@ export default function HeightAnimation({ open, animate, children, + onInit, onOpen, onAnimationEnd, }) diff --git a/packages/dnb-eufemia/src/components/height-animation/__tests__/HeightAnimation.test.tsx b/packages/dnb-eufemia/src/components/height-animation/__tests__/HeightAnimation.test.tsx index 322d90c8b3f..08c901d6561 100644 --- a/packages/dnb-eufemia/src/components/height-animation/__tests__/HeightAnimation.test.tsx +++ b/packages/dnb-eufemia/src/components/height-animation/__tests__/HeightAnimation.test.tsx @@ -8,6 +8,7 @@ import { render, act, fireEvent } from '@testing-library/react' import ToggleButton from '../../ToggleButton' import { wait } from '@testing-library/user-event/dist/utils' import HeightAnimation, { HeightAnimationProps } from '../HeightAnimation' +import AnimateHeight from '../../../shared/AnimateHeight' beforeEach(() => { global.IS_TEST = false @@ -160,6 +161,75 @@ describe('HeightAnimation', () => { }) }) + it('should call onOpen', () => { + const onOpen = jest.fn() + const { rerender } = render() + + expect(document.querySelector('.dnb-height-animation')).toBeFalsy() + + rerender() + + act(() => { + simulateAnimationEnd() + expect(onOpen).toHaveBeenCalledTimes(1) + expect(onOpen).toHaveBeenCalledWith(true) + }) + + rerender() + + act(() => { + simulateAnimationEnd() + expect(onOpen).toHaveBeenCalledTimes(2) + expect(onOpen).toHaveBeenCalledWith(false) + }) + }) + + it('should call onAnimationEnd', () => { + const onAnimationEnd = jest.fn() + const { rerender } = render( + + ) + + expect(document.querySelector('.dnb-height-animation')).toBeFalsy() + + rerender() + + act(() => { + simulateAnimationEnd() + expect(onAnimationEnd).toHaveBeenCalledTimes(1) + expect(onAnimationEnd).toHaveBeenCalledWith('opened') + }) + + rerender() + + act(() => { + simulateAnimationEnd() + expect(onAnimationEnd).toHaveBeenCalledWith('closed') + }) + }) + + it('should call onInit', () => { + const onInit = jest.fn() + const { rerender } = render() + + expect(document.querySelector('.dnb-height-animation')).toBeFalsy() + + rerender() + + act(() => { + simulateAnimationEnd() + expect(onInit).toHaveBeenCalledTimes(1) + expect(onInit).toHaveBeenCalledWith(expect.any(AnimateHeight)) + }) + + rerender() + + act(() => { + simulateAnimationEnd() + expect(onInit).toHaveBeenCalledTimes(1) + }) + }) + it('should have content in DOM when keepInDOM is true', async () => { const { rerender } = render() diff --git a/packages/dnb-eufemia/src/components/height-animation/useHeightAnimation.tsx b/packages/dnb-eufemia/src/components/height-animation/useHeightAnimation.tsx index 5f084cd347f..c5cd67311eb 100644 --- a/packages/dnb-eufemia/src/components/height-animation/useHeightAnimation.tsx +++ b/packages/dnb-eufemia/src/components/height-animation/useHeightAnimation.tsx @@ -19,13 +19,18 @@ export type useHeightAnimationOptions = { */ children?: React.ReactNode | HTMLElement + /** + * Is called once before mounting the component (useLayoutEffect) + */ + onInit?: (instance: AnimateHeight) => void + /** * Is called when fully opened or closed */ onOpen?: (isOpen: boolean) => void /** - * Is called when animation is done and the full height has reached + * Is called when aanimation is done and the full height has been reached. */ onAnimationEnd?: (state: HeightAnimationOnEndTypes) => void } @@ -43,11 +48,12 @@ export function useHeightAnimation( open = null, animate = true, children = null, + onInit = null, onOpen = null, onAnimationEnd = null, }: useHeightAnimationOptions = {} ) { - const animRef = React.useRef(null) + const animRef = React.useRef(null) const [isOpen, setIsOpen] = React.useState(open) const [isVisible, setIsVisible] = React.useState(false) const [isAnimating, setIsAnimating] = React.useState(false) @@ -63,6 +69,10 @@ export function useHeightAnimation( React.useLayoutEffect(() => { animRef.current = new AnimateHeight({ animate }) + if (isInitialRender && onInit) { + onInit(animRef.current) + } + if (isInitialRender && isOpen) { onOpen?.(true) }