@mediamonks/react-kit 1.0.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +125 -0
  3. package/dist/_hooks/useStorybookLog.d.ts +21 -0
  4. package/dist/_hooks/useStorybookLog.js +29 -0
  5. package/dist/_utils/childrenAreEqual.d.ts +2 -0
  6. package/dist/_utils/childrenAreEqual.js +16 -0
  7. package/dist/_utils/getId.d.ts +1 -0
  8. package/dist/_utils/getId.js +4 -0
  9. package/dist/_utils/isNonNullableRecord/isNonNullableRecord.d.ts +9 -0
  10. package/dist/_utils/isNonNullableRecord/isNonNullableRecord.js +6 -0
  11. package/dist/_utils/trimEnd/trimEnd.d.ts +4 -0
  12. package/dist/_utils/trimEnd/trimEnd.js +9 -0
  13. package/dist/components/AutoFill/AutoFill.d.ts +13 -0
  14. package/dist/components/AutoFill/AutoFill.js +33 -0
  15. package/dist/gsap/animations.d.ts +11 -0
  16. package/dist/gsap/animations.js +35 -0
  17. package/dist/gsap/components/SplitTextWrapper/SplitTextWrapper.d.ts +24 -0
  18. package/dist/gsap/components/SplitTextWrapper/SplitTextWrapper.js +28 -0
  19. package/dist/gsap/hooks/useAnimation/useAnimation.d.ts +6 -0
  20. package/dist/gsap/hooks/useAnimation/useAnimation.js +19 -0
  21. package/dist/gsap/hooks/useExposeAnimation/useExposeAnimation.d.ts +6 -0
  22. package/dist/gsap/hooks/useExposeAnimation/useExposeAnimation.js +28 -0
  23. package/dist/gsap/hooks/useExposedAnimation/useExposedAnimation.d.ts +5 -0
  24. package/dist/gsap/hooks/useExposedAnimation/useExposedAnimation.js +13 -0
  25. package/dist/gsap/hooks/useExposedAnimations/useExposedAnimations.d.ts +5 -0
  26. package/dist/gsap/hooks/useExposedAnimations/useExposedAnimations.js +32 -0
  27. package/dist/gsap/hooks/useFlip/useFlip.d.ts +3 -0
  28. package/dist/gsap/hooks/useFlip/useFlip.js +18 -0
  29. package/dist/gsap/hooks/useScrollAnimation/useScrollAnimation.d.ts +9 -0
  30. package/dist/gsap/hooks/useScrollAnimation/useScrollAnimation.js +26 -0
  31. package/dist/gsap/utils/getAnimation/getAnimation.d.ts +4 -0
  32. package/dist/gsap/utils/getAnimation/getAnimation.js +7 -0
  33. package/dist/hocs/ensuredForwardRef/ensuredForwardRef.d.ts +11 -0
  34. package/dist/hocs/ensuredForwardRef/ensuredForwardRef.js +31 -0
  35. package/dist/hooks/useClientSideValue/useClientSideValue.d.ts +11 -0
  36. package/dist/hooks/useClientSideValue/useClientSideValue.js +19 -0
  37. package/dist/hooks/useEventListener/useEventListener.d.ts +2 -0
  38. package/dist/hooks/useEventListener/useEventListener.js +17 -0
  39. package/dist/hooks/useForceRerender/useForceRerender.d.ts +11 -0
  40. package/dist/hooks/useForceRerender/useForceRerender.js +18 -0
  41. package/dist/hooks/useHasFocus/useHasFocus.d.ts +9 -0
  42. package/dist/hooks/useHasFocus/useHasFocus.js +18 -0
  43. package/dist/hooks/useIntersectionObserver/useIntersectionObserver.d.ts +13 -0
  44. package/dist/hooks/useIntersectionObserver/useIntersectionObserver.js +38 -0
  45. package/dist/hooks/useInterval/useInterval.d.ts +8 -0
  46. package/dist/hooks/useInterval/useInterval.js +25 -0
  47. package/dist/hooks/useMediaDuration/useMediaDuration.d.ts +5 -0
  48. package/dist/hooks/useMediaDuration/useMediaDuration.js +20 -0
  49. package/dist/hooks/useMediaQuery/useMediaQuery.d.ts +33 -0
  50. package/dist/hooks/useMediaQuery/useMediaQuery.js +32 -0
  51. package/dist/hooks/useMutationObserver/useMutationObserver.d.ts +16 -0
  52. package/dist/hooks/useMutationObserver/useMutationObserver.js +36 -0
  53. package/dist/hooks/useRafCallback/useRafCallback.d.ts +5 -0
  54. package/dist/hooks/useRafCallback/useRafCallback.js +21 -0
  55. package/dist/hooks/useRefValue/useRefValue.d.ts +11 -0
  56. package/dist/hooks/useRefValue/useRefValue.js +15 -0
  57. package/dist/hooks/useRefs/useRefs.d.ts +5 -0
  58. package/dist/hooks/useRefs/useRefs.js +17 -0
  59. package/dist/hooks/useRefs/useRefs.types.d.ts +15 -0
  60. package/dist/hooks/useRefs/useRefs.types.js +1 -0
  61. package/dist/hooks/useRefs/utils/assertAndUnwrapRefs/assertAndUnwrapRefs.d.ts +14 -0
  62. package/dist/hooks/useRefs/utils/assertAndUnwrapRefs/assertAndUnwrapRefs.js +19 -0
  63. package/dist/hooks/useRefs/utils/unwrapRefs/unwrapRefs.d.ts +6 -0
  64. package/dist/hooks/useRefs/utils/unwrapRefs/unwrapRefs.js +12 -0
  65. package/dist/hooks/useRefs/utils/unwrapRefs/unwrapRefs.types.d.ts +7 -0
  66. package/dist/hooks/useRefs/utils/unwrapRefs/unwrapRefs.types.js +1 -0
  67. package/dist/hooks/useRefs/utils/validateAndUnwrapRefs/validateAndUnwrapRefs.d.ts +12 -0
  68. package/dist/hooks/useRefs/utils/validateAndUnwrapRefs/validateAndUnwrapRefs.js +17 -0
  69. package/dist/hooks/useResizeObserver/useResizeObserver.d.ts +9 -0
  70. package/dist/hooks/useResizeObserver/useResizeObserver.js +22 -0
  71. package/dist/hooks/useStaticValue/useStaticValue.d.ts +6 -0
  72. package/dist/hooks/useStaticValue/useStaticValue.js +11 -0
  73. package/dist/hooks/useToggle/useToggle.d.ts +16 -0
  74. package/dist/hooks/useToggle/useToggle.js +23 -0
  75. package/dist/index.d.ts +44 -0
  76. package/dist/index.js +46 -0
  77. package/dist/lifecycle/components/CrossFlow/CrossFlow.d.ts +3 -0
  78. package/dist/lifecycle/components/CrossFlow/CrossFlow.js +55 -0
  79. package/dist/lifecycle/components/TransitionPresence/TransitionPresence.context.d.ts +4 -0
  80. package/dist/lifecycle/components/TransitionPresence/TransitionPresence.context.js +2 -0
  81. package/dist/lifecycle/components/TransitionPresence/TransitionPresence.d.ts +13 -0
  82. package/dist/lifecycle/components/TransitionPresence/TransitionPresence.js +61 -0
  83. package/dist/lifecycle/hooks/useBeforeMount/useBeforeMount.d.ts +11 -0
  84. package/dist/lifecycle/hooks/useBeforeMount/useBeforeMount.js +21 -0
  85. package/dist/lifecycle/hooks/useBeforeUnmount/useBeforeUnmount.d.ts +11 -0
  86. package/dist/lifecycle/hooks/useBeforeUnmount/useBeforeUnmount.js +39 -0
  87. package/dist/lifecycle/hooks/useIsMounted/useIsMounted.d.ts +13 -0
  88. package/dist/lifecycle/hooks/useIsMounted/useIsMounted.js +34 -0
  89. package/dist/lifecycle/hooks/useIsMountedState/useIsMountedState.d.ts +9 -0
  90. package/dist/lifecycle/hooks/useIsMountedState/useIsMountedState.js +21 -0
  91. package/dist/lifecycle/hooks/useMount/useMount.d.ts +12 -0
  92. package/dist/lifecycle/hooks/useMount/useMount.js +16 -0
  93. package/dist/lifecycle/hooks/useUnmount/useUnmount.d.ts +12 -0
  94. package/dist/lifecycle/hooks/useUnmount/useUnmount.js +19 -0
  95. package/dist/nextjs/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.d.ts +18 -0
  96. package/dist/nextjs/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js +18 -0
  97. package/dist/utils/arrayRef/arrayRef.d.ts +8 -0
  98. package/dist/utils/arrayRef/arrayRef.js +35 -0
  99. package/dist/utils/createTimeout/createTimeout.d.ts +5 -0
  100. package/dist/utils/createTimeout/createTimeout.js +9 -0
  101. package/dist/utils/isRefObject/isRefObject.d.ts +5 -0
  102. package/dist/utils/isRefObject/isRefObject.js +6 -0
  103. package/dist/utils/unref/unref.d.ts +13 -0
  104. package/dist/utils/unref/unref.js +7 -0
  105. package/package.json +131 -0
@@ -0,0 +1,11 @@
1
+ import { useState } from 'react';
2
+ /**
3
+ * Keep track of a value that is initialized once and then never changes.
4
+ *
5
+ * This behavior is similar to `useState`, but the value is never updated.
6
+ */
7
+ export function useStaticValue(initializeFunction) {
8
+ // eslint-disable-next-line react/hook-use-state
9
+ const [value] = useState(initializeFunction);
10
+ return value;
11
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Easily toggle value between two states
3
+ * @param initialValue Whether the toggle should be initially true or false
4
+ *
5
+ * @example
6
+ * ```
7
+ * const [isActive, toggle] = useToggle(false);
8
+ * watchEffect(() => {
9
+ * console.log('active', isActive);
10
+ * }
11
+ * toggle();
12
+ * toggle(false);
13
+ * toggle(true);
14
+ * ```
15
+ */
16
+ export declare function useToggle(initialValue: boolean): readonly [boolean, (force?: boolean) => void];
@@ -0,0 +1,23 @@
1
+ import { useCallback, useState } from 'react';
2
+ /**
3
+ * Easily toggle value between two states
4
+ * @param initialValue Whether the toggle should be initially true or false
5
+ *
6
+ * @example
7
+ * ```
8
+ * const [isActive, toggle] = useToggle(false);
9
+ * watchEffect(() => {
10
+ * console.log('active', isActive);
11
+ * }
12
+ * toggle();
13
+ * toggle(false);
14
+ * toggle(true);
15
+ * ```
16
+ */
17
+ export function useToggle(initialValue) {
18
+ const [state, setState] = useState(initialValue);
19
+ const toggle = useCallback((force) => {
20
+ setState((oldValue) => (force === undefined ? !oldValue : force));
21
+ }, [setState]);
22
+ return [state, toggle];
23
+ }
@@ -0,0 +1,44 @@
1
+ export * from './components/AutoFill/AutoFill.js';
2
+ export * from './gsap/components/SplitTextWrapper/SplitTextWrapper.js';
3
+ export * from './gsap/hooks/useAnimation/useAnimation.js';
4
+ export * from './gsap/hooks/useExposeAnimation/useExposeAnimation.js';
5
+ export * from './gsap/hooks/useExposedAnimation/useExposedAnimation.js';
6
+ export * from './gsap/hooks/useExposedAnimations/useExposedAnimations.js';
7
+ export * from './gsap/hooks/useFlip/useFlip.js';
8
+ export * from './gsap/hooks/useScrollAnimation/useScrollAnimation.js';
9
+ export * from './gsap/utils/getAnimation/getAnimation.js';
10
+ export * from './hocs/ensuredForwardRef/ensuredForwardRef.js';
11
+ export * from './hooks/useClientSideValue/useClientSideValue.js';
12
+ export * from './hooks/useEventListener/useEventListener.js';
13
+ export * from './hooks/useForceRerender/useForceRerender.js';
14
+ export * from './hooks/useHasFocus/useHasFocus.js';
15
+ export * from './hooks/useIntersectionObserver/useIntersectionObserver.js';
16
+ export * from './hooks/useInterval/useInterval.js';
17
+ export * from './hooks/useMediaDuration/useMediaDuration.js';
18
+ export * from './hooks/useMediaQuery/useMediaQuery.js';
19
+ export * from './hooks/useMutationObserver/useMutationObserver.js';
20
+ export * from './hooks/useRafCallback/useRafCallback.js';
21
+ export * from './hooks/useRefValue/useRefValue.js';
22
+ export * from './hooks/useRefs/useRefs.js';
23
+ export * from './hooks/useRefs/useRefs.types.js';
24
+ export * from './hooks/useRefs/utils/assertAndUnwrapRefs/assertAndUnwrapRefs.js';
25
+ export * from './hooks/useRefs/utils/unwrapRefs/unwrapRefs.js';
26
+ export * from './hooks/useRefs/utils/unwrapRefs/unwrapRefs.types.js';
27
+ export * from './hooks/useRefs/utils/validateAndUnwrapRefs/validateAndUnwrapRefs.js';
28
+ export * from './hooks/useResizeObserver/useResizeObserver.js';
29
+ export * from './hooks/useStaticValue/useStaticValue.js';
30
+ export * from './hooks/useToggle/useToggle.js';
31
+ export * from './lifecycle/hooks/useBeforeMount/useBeforeMount.js';
32
+ export * from './lifecycle/hooks/useIsMounted/useIsMounted.js';
33
+ export * from './lifecycle/hooks/useIsMountedState/useIsMountedState.js';
34
+ export * from './lifecycle/hooks/useMount/useMount.js';
35
+ export * from './lifecycle/hooks/useUnmount/useUnmount.js';
36
+ export * from './nextjs/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js';
37
+ export * from './utils/arrayRef/arrayRef.js';
38
+ export * from './utils/createTimeout/createTimeout.js';
39
+ export * from './utils/isRefObject/isRefObject.js';
40
+ export * from './utils/unref/unref.js';
41
+ export { CrossFlow } from './lifecycle/components/CrossFlow/CrossFlow.js';
42
+ export { TransitionPresenceContext } from './lifecycle/components/TransitionPresence/TransitionPresence.context.js';
43
+ export { TransitionPresence } from './lifecycle/components/TransitionPresence/TransitionPresence.js';
44
+ export { useBeforeUnmount, type BeforeUnmountCallback, } from './lifecycle/hooks/useBeforeUnmount/useBeforeUnmount.js';
package/dist/index.js ADDED
@@ -0,0 +1,46 @@
1
+ /* PLOP_ADD_EXPORT */
2
+ export * from './components/AutoFill/AutoFill.js';
3
+ export * from './gsap/components/SplitTextWrapper/SplitTextWrapper.js';
4
+ export * from './gsap/hooks/useAnimation/useAnimation.js';
5
+ export * from './gsap/hooks/useExposeAnimation/useExposeAnimation.js';
6
+ export * from './gsap/hooks/useExposedAnimation/useExposedAnimation.js';
7
+ export * from './gsap/hooks/useExposedAnimations/useExposedAnimations.js';
8
+ export * from './gsap/hooks/useFlip/useFlip.js';
9
+ export * from './gsap/hooks/useScrollAnimation/useScrollAnimation.js';
10
+ export * from './gsap/utils/getAnimation/getAnimation.js';
11
+ export * from './hocs/ensuredForwardRef/ensuredForwardRef.js';
12
+ export * from './hooks/useClientSideValue/useClientSideValue.js';
13
+ export * from './hooks/useEventListener/useEventListener.js';
14
+ export * from './hooks/useForceRerender/useForceRerender.js';
15
+ export * from './hooks/useHasFocus/useHasFocus.js';
16
+ export * from './hooks/useIntersectionObserver/useIntersectionObserver.js';
17
+ export * from './hooks/useInterval/useInterval.js';
18
+ export * from './hooks/useMediaDuration/useMediaDuration.js';
19
+ export * from './hooks/useMediaQuery/useMediaQuery.js';
20
+ export * from './hooks/useMutationObserver/useMutationObserver.js';
21
+ export * from './hooks/useRafCallback/useRafCallback.js';
22
+ export * from './hooks/useRefValue/useRefValue.js';
23
+ export * from './hooks/useRefs/useRefs.js';
24
+ export * from './hooks/useRefs/useRefs.types.js';
25
+ export * from './hooks/useRefs/utils/assertAndUnwrapRefs/assertAndUnwrapRefs.js';
26
+ export * from './hooks/useRefs/utils/unwrapRefs/unwrapRefs.js';
27
+ export * from './hooks/useRefs/utils/unwrapRefs/unwrapRefs.types.js';
28
+ export * from './hooks/useRefs/utils/validateAndUnwrapRefs/validateAndUnwrapRefs.js';
29
+ export * from './hooks/useResizeObserver/useResizeObserver.js';
30
+ export * from './hooks/useStaticValue/useStaticValue.js';
31
+ export * from './hooks/useToggle/useToggle.js';
32
+ export * from './lifecycle/hooks/useBeforeMount/useBeforeMount.js';
33
+ export * from './lifecycle/hooks/useIsMounted/useIsMounted.js';
34
+ export * from './lifecycle/hooks/useIsMountedState/useIsMountedState.js';
35
+ export * from './lifecycle/hooks/useMount/useMount.js';
36
+ export * from './lifecycle/hooks/useUnmount/useUnmount.js';
37
+ export * from './nextjs/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js';
38
+ export * from './utils/arrayRef/arrayRef.js';
39
+ export * from './utils/createTimeout/createTimeout.js';
40
+ export * from './utils/isRefObject/isRefObject.js';
41
+ export * from './utils/unref/unref.js';
42
+ // Custom exports for external use only
43
+ export { CrossFlow } from './lifecycle/components/CrossFlow/CrossFlow.js';
44
+ export { TransitionPresenceContext } from './lifecycle/components/TransitionPresence/TransitionPresence.context.js';
45
+ export { TransitionPresence } from './lifecycle/components/TransitionPresence/TransitionPresence.js';
46
+ export { useBeforeUnmount, } from './lifecycle/hooks/useBeforeUnmount/useBeforeUnmount.js';
@@ -0,0 +1,3 @@
1
+ import { type ReactElement } from 'react';
2
+ import { type TransitionPresenceProps } from '../TransitionPresence/TransitionPresence.js';
3
+ export declare function CrossFlow({ children, onChildrenMounted, ...props }: TransitionPresenceProps): ReactElement;
@@ -0,0 +1,55 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { createElement as _createElement } from "react";
3
+ import { cloneElement, useCallback, useEffect, useRef, useState } from 'react';
4
+ import { childrenAreEqual } from '../../../_utils/childrenAreEqual.js';
5
+ import { getId } from '../../../_utils/getId.js';
6
+ import { useIsMounted } from '../../hooks/useIsMounted/useIsMounted.js';
7
+ import { TransitionPresence, } from '../TransitionPresence/TransitionPresence.js';
8
+ export function CrossFlow({ children, onChildrenMounted, ...props }) {
9
+ const previousChildren = useRef(children);
10
+ const [queue, setQueue] = useState(() => children === null
11
+ ? {}
12
+ : {
13
+ [getId()]: children,
14
+ });
15
+ const isMounted = useIsMounted();
16
+ useEffect(() => {
17
+ // Don't do anything during the first render
18
+ if (!isMounted.current) {
19
+ return;
20
+ }
21
+ // If the children are equal we don't want to do anything
22
+ const areChildrenEqual = childrenAreEqual(children, previousChildren.current);
23
+ previousChildren.current = children;
24
+ if (areChildrenEqual) {
25
+ return;
26
+ }
27
+ // Add new children to the queue and remove the old children instance for
28
+ // its key to start the out transition
29
+ setQueue((value) => {
30
+ const emptyQueue = {};
31
+ // eslint-disable-next-line guard-for-in
32
+ for (const key in value) {
33
+ emptyQueue[key] = null;
34
+ }
35
+ if (children === null) {
36
+ return emptyQueue;
37
+ }
38
+ return {
39
+ ...emptyQueue,
40
+ [getId()]: children,
41
+ };
42
+ });
43
+ }, [children, isMounted, previousChildren]);
44
+ const onChildrenMountedCleanup = useCallback((_children) => {
45
+ setQueue((value) => {
46
+ if ('key' in _children && _children.key !== null) {
47
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
48
+ delete value[_children.key];
49
+ }
50
+ return { ...value };
51
+ });
52
+ onChildrenMounted?.(_children, null);
53
+ }, [onChildrenMounted]);
54
+ return (_jsx(_Fragment, { children: Object.entries(queue).map(([key, queuedChildren]) => (_createElement(TransitionPresence, { onChildrenMounted: onChildrenMountedCleanup, ...props, key: key }, queuedChildren && cloneElement(queuedChildren, { key })))) }));
55
+ }
@@ -0,0 +1,4 @@
1
+ import { type RefObject } from 'react';
2
+ import type { BeforeUnmountCallback } from '../../hooks/useBeforeUnmount/useBeforeUnmount.js';
3
+ export type TransitionPresenceContextType = Set<RefObject<BeforeUnmountCallback>> | undefined;
4
+ export declare const TransitionPresenceContext: import("react").Context<TransitionPresenceContextType>;
@@ -0,0 +1,2 @@
1
+ import { createContext } from 'react';
2
+ export const TransitionPresenceContext = createContext(undefined);
@@ -0,0 +1,13 @@
1
+ import { type ReactElement } from 'react';
2
+ export type TransitionPresenceProps = {
3
+ children: ReactElement | null;
4
+ onPreviousChildrenUnmounting?(previousChildren: ReactElement | null, children: ReactElement | null): void | Promise<void>;
5
+ onPreviousChildrenUnmounted?(previousChildren: ReactElement | null, children: ReactElement | null): void | Promise<void>;
6
+ onChildrenMounted?(previousChildren: ReactElement | null, children: ReactElement | null): void | Promise<void>;
7
+ };
8
+ /**
9
+ * Will defer transition in new children by waiting on the
10
+ * `BeforeUnmountCallback`s that are registered using the `useBeforeUnmount`
11
+ * hook.
12
+ */
13
+ export declare function TransitionPresence({ children, onPreviousChildrenUnmounting, onPreviousChildrenUnmounted, onChildrenMounted, }: TransitionPresenceProps): ReactElement;
@@ -0,0 +1,61 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useState, } from 'react';
3
+ import { childrenAreEqual } from '../../../_utils/childrenAreEqual.js';
4
+ import { useRefValue } from '../../../hooks/useRefValue/useRefValue.js';
5
+ import { createTimeout } from '../../../index.js';
6
+ import { useTransitionPresenceBeforeUnmount, } from '../../hooks/useBeforeUnmount/useBeforeUnmount.js';
7
+ import { TransitionPresenceContext } from './TransitionPresence.context.js';
8
+ /**
9
+ * Will defer transition in new children by waiting on the
10
+ * `BeforeUnmountCallback`s that are registered using the `useBeforeUnmount`
11
+ * hook.
12
+ */
13
+ export function TransitionPresence({ children, onPreviousChildrenUnmounting, onPreviousChildrenUnmounted, onChildrenMounted, }) {
14
+ const beforeUnmountCallbacks = useMemo(() => new Set(), []);
15
+ const [previousChildren, setPreviousChildren] = useState(children);
16
+ const onPreviousChildrenUnmountingRef = useRefValue(onPreviousChildrenUnmounting);
17
+ const onPreviousChildrenUnmountedRef = useRefValue(onPreviousChildrenUnmounted);
18
+ const onChildrenMountedRef = useRefValue(onChildrenMounted);
19
+ const beforeUnmountPreviousChildren = useCallback(async (abortSignal) => {
20
+ const promises = [];
21
+ for (const callback of beforeUnmountCallbacks) {
22
+ promises.push(callback.current?.(abortSignal));
23
+ }
24
+ await Promise.all(promises);
25
+ }, [beforeUnmountCallbacks]);
26
+ useEffect(() => {
27
+ if (childrenAreEqual(children, previousChildren)) {
28
+ setPreviousChildren(children);
29
+ return;
30
+ }
31
+ const abortController = new AbortController();
32
+ (async () => {
33
+ onPreviousChildrenUnmountingRef.current?.(previousChildren, children);
34
+ // Defer children update for before unmount lifecycle
35
+ await beforeUnmountPreviousChildren(abortController.signal);
36
+ setPreviousChildren(null);
37
+ // Wait a tick after removing previous children to make sure new children
38
+ // are re-initialized
39
+ await createTimeout();
40
+ onPreviousChildrenUnmountedRef.current?.(previousChildren, children);
41
+ // Set new children
42
+ setPreviousChildren(children);
43
+ await createTimeout();
44
+ onChildrenMountedRef.current?.(previousChildren, children);
45
+ })();
46
+ return () => {
47
+ abortController.abort();
48
+ };
49
+ }, [
50
+ beforeUnmountCallbacks,
51
+ beforeUnmountPreviousChildren,
52
+ children,
53
+ onChildrenMountedRef,
54
+ onPreviousChildrenUnmountedRef,
55
+ onPreviousChildrenUnmountingRef,
56
+ previousChildren,
57
+ ]);
58
+ // Apply same effect when TransitionPresence in tree updates
59
+ useTransitionPresenceBeforeUnmount(beforeUnmountPreviousChildren);
60
+ return (_jsx(TransitionPresenceContext.Provider, { value: beforeUnmountCallbacks, children: previousChildren }));
61
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Executes a callback during the initial render, before mounting, but not during subsequent
3
+ * renders.
4
+ *
5
+ * Opposed to `useEffect` / `useMount`, the callback is executed synchronously,
6
+ * before the component is mounted.
7
+ *
8
+ * @param callback A function to be executed during the initial render, before mounting, but not
9
+ * during subsequent renders.
10
+ */
11
+ export declare function useBeforeMount(callback: () => void): void;
@@ -0,0 +1,21 @@
1
+ import { useRef } from 'react';
2
+ import { useMount } from '../useMount/useMount.js';
3
+ /**
4
+ * Executes a callback during the initial render, before mounting, but not during subsequent
5
+ * renders.
6
+ *
7
+ * Opposed to `useEffect` / `useMount`, the callback is executed synchronously,
8
+ * before the component is mounted.
9
+ *
10
+ * @param callback A function to be executed during the initial render, before mounting, but not
11
+ * during subsequent renders.
12
+ */
13
+ export function useBeforeMount(callback) {
14
+ const isBeforeMount = useRef(true);
15
+ if (isBeforeMount.current) {
16
+ callback();
17
+ }
18
+ useMount(() => {
19
+ isBeforeMount.current = false;
20
+ });
21
+ }
@@ -0,0 +1,11 @@
1
+ export type BeforeUnmountCallback = (abortSignal: AbortSignal) => PromiseLike<unknown> | void;
2
+ /**
3
+ * Executes async callback to defer unmounting of children in nearest
4
+ * TransitionPresence boundary
5
+ */
6
+ export declare function useBeforeUnmount(callback: BeforeUnmountCallback): void;
7
+ /**
8
+ * useBeforeUnmount without the warning, this should only be used within the
9
+ * <TransitionPresence> component in this package.
10
+ */
11
+ export declare function useTransitionPresenceBeforeUnmount(callback: BeforeUnmountCallback): void;
@@ -0,0 +1,39 @@
1
+ import { useContext, useEffect } from 'react';
2
+ import { useRefValue } from '../../../hooks/useRefValue/useRefValue.js';
3
+ import { TransitionPresenceContext } from '../../components/TransitionPresence/TransitionPresence.context.js';
4
+ /**
5
+ * Executes async callback to defer unmounting of children in nearest
6
+ * TransitionPresence boundary
7
+ */
8
+ export function useBeforeUnmount(callback) {
9
+ const transitionPresence = useContext(TransitionPresenceContext);
10
+ const callbackRef = useRefValue(callback);
11
+ if (transitionPresence === undefined) {
12
+ // eslint-disable-next-line no-console
13
+ console.warn('Component is not rendered in the context of a TransitionPresence');
14
+ }
15
+ useEffect(() => {
16
+ queueMicrotask(() => {
17
+ transitionPresence?.add(callbackRef);
18
+ });
19
+ return () => {
20
+ transitionPresence?.delete(callbackRef);
21
+ };
22
+ }, [transitionPresence, callbackRef]);
23
+ }
24
+ /**
25
+ * useBeforeUnmount without the warning, this should only be used within the
26
+ * <TransitionPresence> component in this package.
27
+ */
28
+ export function useTransitionPresenceBeforeUnmount(callback) {
29
+ const transitionPresence = useContext(TransitionPresenceContext);
30
+ const callbackRef = useRefValue(callback);
31
+ useEffect(() => {
32
+ queueMicrotask(() => {
33
+ transitionPresence?.add(callbackRef);
34
+ });
35
+ return () => {
36
+ transitionPresence?.delete(callbackRef);
37
+ };
38
+ }, [transitionPresence, callbackRef]);
39
+ }
@@ -0,0 +1,13 @@
1
+ import { type RefObject } from 'react';
2
+ /**
3
+ * Keeps track of whether the component is mounted, and returns a ref object that is updated
4
+ * accordingly.
5
+ *
6
+ * - `isMounted.current` is `false` before the component is mounted
7
+ * - `isMounted.current` is `true` after the component is mounted
8
+ * - `isMounted.current` is `false` during the unmount cleanup phase and after the component is
9
+ * unmounted
10
+ *
11
+ * @returns A boolean ref object that reflects whether the component is mounted.
12
+ */
13
+ export declare function useIsMounted(): RefObject<boolean>;
@@ -0,0 +1,34 @@
1
+ import { useEffect, useRef } from 'react';
2
+ /**
3
+ * Keeps track of whether the component is mounted, and returns a ref object that is updated
4
+ * accordingly.
5
+ *
6
+ * - `isMounted.current` is `false` before the component is mounted
7
+ * - `isMounted.current` is `true` after the component is mounted
8
+ * - `isMounted.current` is `false` during the unmount cleanup phase and after the component is
9
+ * unmounted
10
+ *
11
+ * @returns A boolean ref object that reflects whether the component is mounted.
12
+ */
13
+ export function useIsMounted() {
14
+ const isMounted = useRef(false);
15
+ useEffect(() => {
16
+ let unmounted = false;
17
+ // Delay setting this to true until all other useEffects have run
18
+ // however, this can be too late if there are any "setState" actions inside
19
+ // the other useEffects that cause an immediate re-render in the same tick.
20
+ // This is okay, since multiple renders in the same tick can still be considered
21
+ // as the mounting phase, and very rare.
22
+ queueMicrotask(() => {
23
+ if (unmounted) {
24
+ return;
25
+ }
26
+ isMounted.current = true;
27
+ });
28
+ return () => {
29
+ unmounted = true;
30
+ isMounted.current = false;
31
+ };
32
+ }, []);
33
+ return isMounted;
34
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Exposes the mounted state that is updated after the component is mounted.
3
+ *
4
+ * This hook uses setState to update the state after the component is mounted, which means that
5
+ * the component will be re-rendered after the first render.
6
+ *
7
+ * @returns A boolean indicating whether the component is mounted.
8
+ */
9
+ export declare function useIsMountedState(): boolean;
@@ -0,0 +1,21 @@
1
+ import { useState } from 'react';
2
+ import { useMount } from '../useMount/useMount.js';
3
+ /**
4
+ * Exposes the mounted state that is updated after the component is mounted.
5
+ *
6
+ * This hook uses setState to update the state after the component is mounted, which means that
7
+ * the component will be re-rendered after the first render.
8
+ *
9
+ * @returns A boolean indicating whether the component is mounted.
10
+ */
11
+ export function useIsMountedState() {
12
+ const [isMounted, setIsMounted] = useState(false);
13
+ useMount(() => {
14
+ // make sure that mounting has finished
15
+ // and then trigger a render in the next "tick"
16
+ queueMicrotask(() => {
17
+ setIsMounted(true);
18
+ });
19
+ });
20
+ return isMounted;
21
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * React lifecycle hook that calls a function after the component is mounted.
3
+ * @param callbackFunction function to be called when the component is mounted
4
+ *
5
+ * @example
6
+ * ```
7
+ * useMount(() => {
8
+ * console.log('component is mounted');
9
+ * })
10
+ * ```
11
+ */
12
+ export declare function useMount(callbackFunction: () => void): void;
@@ -0,0 +1,16 @@
1
+ import { useEffect } from 'react';
2
+ /**
3
+ * React lifecycle hook that calls a function after the component is mounted.
4
+ * @param callbackFunction function to be called when the component is mounted
5
+ *
6
+ * @example
7
+ * ```
8
+ * useMount(() => {
9
+ * console.log('component is mounted');
10
+ * })
11
+ * ```
12
+ */
13
+ export function useMount(callbackFunction) {
14
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15
+ useEffect(callbackFunction, []);
16
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * React lifecycle hook that calls a function after the component is unmounted.
3
+ * @param callbackFunction function to be called when the component is unmounted
4
+ *
5
+ * @example
6
+ * ```
7
+ * useUnmount(() => {
8
+ * console.log('component is unmounted');
9
+ * })
10
+ * ```
11
+ */
12
+ export declare function useUnmount(callbackFunction: () => void): void;
@@ -0,0 +1,19 @@
1
+ import { useEffect } from 'react';
2
+ import { useRefValue } from '../../../hooks/useRefValue/useRefValue.js';
3
+ /**
4
+ * React lifecycle hook that calls a function after the component is unmounted.
5
+ * @param callbackFunction function to be called when the component is unmounted
6
+ *
7
+ * @example
8
+ * ```
9
+ * useUnmount(() => {
10
+ * console.log('component is unmounted');
11
+ * })
12
+ * ```
13
+ */
14
+ export function useUnmount(callbackFunction) {
15
+ const callbackRef = useRefValue(callbackFunction);
16
+ useEffect(() => () => {
17
+ callbackRef.current?.();
18
+ }, [callbackRef]);
19
+ }
@@ -0,0 +1,18 @@
1
+ import { useEffect } from 'react';
2
+ /**
3
+ * The React documentation says about useLayoutEffect:
4
+ *
5
+ * "The signature is identical to useEffect, but it fires synchronously after all DOM mutations."
6
+ *
7
+ * That means this hook is a browser hook. But React code could be generated from the server without the Window API.
8
+ *
9
+ * If you're using NextJS, you'll have this error message:
10
+ * "Warning: useLayoutEffect does nothing on the server,
11
+ * because its effect cannot be encoded into the server renderer's output format.
12
+ * This will lead to a mismatch between the initial, non-hydrated UI and the intended UI.
13
+ * To avoid this, useLayoutEffect should only be used in components that render exclusively on the client.
14
+ * See https://reactjs.org/link/uselayouteffect-ssr for common fixes."
15
+ *
16
+ * This hook fixes this problem by switching between useEffect and useLayoutEffect following the execution environment.
17
+ */
18
+ export declare const useIsomorphicLayoutEffect: typeof useEffect;
@@ -0,0 +1,18 @@
1
+ import { useEffect, useLayoutEffect } from 'react';
2
+ /**
3
+ * The React documentation says about useLayoutEffect:
4
+ *
5
+ * "The signature is identical to useEffect, but it fires synchronously after all DOM mutations."
6
+ *
7
+ * That means this hook is a browser hook. But React code could be generated from the server without the Window API.
8
+ *
9
+ * If you're using NextJS, you'll have this error message:
10
+ * "Warning: useLayoutEffect does nothing on the server,
11
+ * because its effect cannot be encoded into the server renderer's output format.
12
+ * This will lead to a mismatch between the initial, non-hydrated UI and the intended UI.
13
+ * To avoid this, useLayoutEffect should only be used in components that render exclusively on the client.
14
+ * See https://reactjs.org/link/uselayouteffect-ssr for common fixes."
15
+ *
16
+ * This hook fixes this problem by switching between useEffect and useLayoutEffect following the execution environment.
17
+ */
18
+ export const useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
@@ -0,0 +1,8 @@
1
+ /// <reference types="lodash" resolution-mode="require"/>
2
+ import type { MutableRefObject } from 'react';
3
+ /**
4
+ * Helper to set element in RefObject<Array>
5
+ */
6
+ declare function arrayRefInternal<T extends MutableRefObject<Array<unknown> | null>>(ref: T, index: number): (element: NonNullable<T['current']>[number]) => void;
7
+ export declare const arrayRef: typeof arrayRefInternal & import("lodash").MemoizedFunction;
8
+ export {};
@@ -0,0 +1,35 @@
1
+ import { memoize } from 'lodash-es';
2
+ import { trimEnd } from '../../_utils/trimEnd/trimEnd.js';
3
+ /**
4
+ * Helper to set element in RefObject<Array>
5
+ */
6
+ function arrayRefInternal(ref, index) {
7
+ return (element) => {
8
+ if (ref.current === null) {
9
+ ref.current = [];
10
+ }
11
+ ref.current[index] = element;
12
+ if (element === null) {
13
+ trimEnd(ref.current, null);
14
+ }
15
+ };
16
+ }
17
+ const refMap = new Map();
18
+ let uniqueValueCounter = 0;
19
+ /**
20
+ * Turns a ref and index into a unique key
21
+ * This is needed because the memoize function only uses string keys,
22
+ * and we need to use a ref as a key.
23
+ * The Map is used to make sure that the same ref always gets the same unique number,
24
+ * since Maps can use objects as keys.
25
+ *
26
+ * @param ref
27
+ * @param index
28
+ */
29
+ function getMemoizeKeyForRefAndIndex(ref, index) {
30
+ if (!refMap.has(ref)) {
31
+ refMap.set(ref, ++uniqueValueCounter);
32
+ }
33
+ return `${refMap.get(ref)}_${index}`;
34
+ }
35
+ export const arrayRef = memoize(arrayRefInternal, (ref, index) => getMemoizeKeyForRefAndIndex(ref, index));
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Returns a promise that resolves after given amount of time. Use the default
3
+ * value of `0` to wait for the next tick.
4
+ */
5
+ export declare function createTimeout(ms?: number): Promise<void>;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Returns a promise that resolves after given amount of time. Use the default
3
+ * value of `0` to wait for the next tick.
4
+ */
5
+ export function createTimeout(ms = 0) {
6
+ return new Promise((resolve) => {
7
+ setTimeout(resolve, ms);
8
+ });
9
+ }
@@ -0,0 +1,5 @@
1
+ import type { RefObject } from 'react';
2
+ /**
3
+ * Type guard to check if a value is a RefObject
4
+ */
5
+ export declare function isRefObject(target: unknown): target is RefObject<unknown>;