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..77935d55e98 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 animation is done and the full height is 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)
}