@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.
- package/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/_hooks/useStorybookLog.d.ts +21 -0
- package/dist/_hooks/useStorybookLog.js +29 -0
- package/dist/_utils/childrenAreEqual.d.ts +2 -0
- package/dist/_utils/childrenAreEqual.js +16 -0
- package/dist/_utils/getId.d.ts +1 -0
- package/dist/_utils/getId.js +4 -0
- package/dist/_utils/isNonNullableRecord/isNonNullableRecord.d.ts +9 -0
- package/dist/_utils/isNonNullableRecord/isNonNullableRecord.js +6 -0
- package/dist/_utils/trimEnd/trimEnd.d.ts +4 -0
- package/dist/_utils/trimEnd/trimEnd.js +9 -0
- package/dist/components/AutoFill/AutoFill.d.ts +13 -0
- package/dist/components/AutoFill/AutoFill.js +33 -0
- package/dist/gsap/animations.d.ts +11 -0
- package/dist/gsap/animations.js +35 -0
- package/dist/gsap/components/SplitTextWrapper/SplitTextWrapper.d.ts +24 -0
- package/dist/gsap/components/SplitTextWrapper/SplitTextWrapper.js +28 -0
- package/dist/gsap/hooks/useAnimation/useAnimation.d.ts +6 -0
- package/dist/gsap/hooks/useAnimation/useAnimation.js +19 -0
- package/dist/gsap/hooks/useExposeAnimation/useExposeAnimation.d.ts +6 -0
- package/dist/gsap/hooks/useExposeAnimation/useExposeAnimation.js +28 -0
- package/dist/gsap/hooks/useExposedAnimation/useExposedAnimation.d.ts +5 -0
- package/dist/gsap/hooks/useExposedAnimation/useExposedAnimation.js +13 -0
- package/dist/gsap/hooks/useExposedAnimations/useExposedAnimations.d.ts +5 -0
- package/dist/gsap/hooks/useExposedAnimations/useExposedAnimations.js +32 -0
- package/dist/gsap/hooks/useFlip/useFlip.d.ts +3 -0
- package/dist/gsap/hooks/useFlip/useFlip.js +18 -0
- package/dist/gsap/hooks/useScrollAnimation/useScrollAnimation.d.ts +9 -0
- package/dist/gsap/hooks/useScrollAnimation/useScrollAnimation.js +26 -0
- package/dist/gsap/utils/getAnimation/getAnimation.d.ts +4 -0
- package/dist/gsap/utils/getAnimation/getAnimation.js +7 -0
- package/dist/hocs/ensuredForwardRef/ensuredForwardRef.d.ts +11 -0
- package/dist/hocs/ensuredForwardRef/ensuredForwardRef.js +31 -0
- package/dist/hooks/useClientSideValue/useClientSideValue.d.ts +11 -0
- package/dist/hooks/useClientSideValue/useClientSideValue.js +19 -0
- package/dist/hooks/useEventListener/useEventListener.d.ts +2 -0
- package/dist/hooks/useEventListener/useEventListener.js +17 -0
- package/dist/hooks/useForceRerender/useForceRerender.d.ts +11 -0
- package/dist/hooks/useForceRerender/useForceRerender.js +18 -0
- package/dist/hooks/useHasFocus/useHasFocus.d.ts +9 -0
- package/dist/hooks/useHasFocus/useHasFocus.js +18 -0
- package/dist/hooks/useIntersectionObserver/useIntersectionObserver.d.ts +13 -0
- package/dist/hooks/useIntersectionObserver/useIntersectionObserver.js +38 -0
- package/dist/hooks/useInterval/useInterval.d.ts +8 -0
- package/dist/hooks/useInterval/useInterval.js +25 -0
- package/dist/hooks/useMediaDuration/useMediaDuration.d.ts +5 -0
- package/dist/hooks/useMediaDuration/useMediaDuration.js +20 -0
- package/dist/hooks/useMediaQuery/useMediaQuery.d.ts +33 -0
- package/dist/hooks/useMediaQuery/useMediaQuery.js +32 -0
- package/dist/hooks/useMutationObserver/useMutationObserver.d.ts +16 -0
- package/dist/hooks/useMutationObserver/useMutationObserver.js +36 -0
- package/dist/hooks/useRafCallback/useRafCallback.d.ts +5 -0
- package/dist/hooks/useRafCallback/useRafCallback.js +21 -0
- package/dist/hooks/useRefValue/useRefValue.d.ts +11 -0
- package/dist/hooks/useRefValue/useRefValue.js +15 -0
- package/dist/hooks/useRefs/useRefs.d.ts +5 -0
- package/dist/hooks/useRefs/useRefs.js +17 -0
- package/dist/hooks/useRefs/useRefs.types.d.ts +15 -0
- package/dist/hooks/useRefs/useRefs.types.js +1 -0
- package/dist/hooks/useRefs/utils/assertAndUnwrapRefs/assertAndUnwrapRefs.d.ts +14 -0
- package/dist/hooks/useRefs/utils/assertAndUnwrapRefs/assertAndUnwrapRefs.js +19 -0
- package/dist/hooks/useRefs/utils/unwrapRefs/unwrapRefs.d.ts +6 -0
- package/dist/hooks/useRefs/utils/unwrapRefs/unwrapRefs.js +12 -0
- package/dist/hooks/useRefs/utils/unwrapRefs/unwrapRefs.types.d.ts +7 -0
- package/dist/hooks/useRefs/utils/unwrapRefs/unwrapRefs.types.js +1 -0
- package/dist/hooks/useRefs/utils/validateAndUnwrapRefs/validateAndUnwrapRefs.d.ts +12 -0
- package/dist/hooks/useRefs/utils/validateAndUnwrapRefs/validateAndUnwrapRefs.js +17 -0
- package/dist/hooks/useResizeObserver/useResizeObserver.d.ts +9 -0
- package/dist/hooks/useResizeObserver/useResizeObserver.js +22 -0
- package/dist/hooks/useStaticValue/useStaticValue.d.ts +6 -0
- package/dist/hooks/useStaticValue/useStaticValue.js +11 -0
- package/dist/hooks/useToggle/useToggle.d.ts +16 -0
- package/dist/hooks/useToggle/useToggle.js +23 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +46 -0
- package/dist/lifecycle/components/CrossFlow/CrossFlow.d.ts +3 -0
- package/dist/lifecycle/components/CrossFlow/CrossFlow.js +55 -0
- package/dist/lifecycle/components/TransitionPresence/TransitionPresence.context.d.ts +4 -0
- package/dist/lifecycle/components/TransitionPresence/TransitionPresence.context.js +2 -0
- package/dist/lifecycle/components/TransitionPresence/TransitionPresence.d.ts +13 -0
- package/dist/lifecycle/components/TransitionPresence/TransitionPresence.js +61 -0
- package/dist/lifecycle/hooks/useBeforeMount/useBeforeMount.d.ts +11 -0
- package/dist/lifecycle/hooks/useBeforeMount/useBeforeMount.js +21 -0
- package/dist/lifecycle/hooks/useBeforeUnmount/useBeforeUnmount.d.ts +11 -0
- package/dist/lifecycle/hooks/useBeforeUnmount/useBeforeUnmount.js +39 -0
- package/dist/lifecycle/hooks/useIsMounted/useIsMounted.d.ts +13 -0
- package/dist/lifecycle/hooks/useIsMounted/useIsMounted.js +34 -0
- package/dist/lifecycle/hooks/useIsMountedState/useIsMountedState.d.ts +9 -0
- package/dist/lifecycle/hooks/useIsMountedState/useIsMountedState.js +21 -0
- package/dist/lifecycle/hooks/useMount/useMount.d.ts +12 -0
- package/dist/lifecycle/hooks/useMount/useMount.js +16 -0
- package/dist/lifecycle/hooks/useUnmount/useUnmount.d.ts +12 -0
- package/dist/lifecycle/hooks/useUnmount/useUnmount.js +19 -0
- package/dist/nextjs/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.d.ts +18 -0
- package/dist/nextjs/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js +18 -0
- package/dist/utils/arrayRef/arrayRef.d.ts +8 -0
- package/dist/utils/arrayRef/arrayRef.js +35 -0
- package/dist/utils/createTimeout/createTimeout.d.ts +5 -0
- package/dist/utils/createTimeout/createTimeout.js +9 -0
- package/dist/utils/isRefObject/isRefObject.d.ts +5 -0
- package/dist/utils/isRefObject/isRefObject.js +6 -0
- package/dist/utils/unref/unref.d.ts +13 -0
- package/dist/utils/unref/unref.js +7 -0
- 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
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -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,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,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));
|