@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Media.Monks
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,125 @@
1
+ [![npm version](https://img.shields.io/npm/v/@mediamonks/react-kit)](https://www.npmjs.com/package/@mediamonks/react-kit)
2
+ [![npm downloads](https://img.shields.io/npm/dm/@mediamonks/react-kit)](https://www.npmjs.com/package/@mediamonks/react-kit)
3
+
4
+ # @mediamonks/react-kit
5
+
6
+ Collection of commonly used React hooks.
7
+
8
+ ## Getting started
9
+
10
+ ### Installing
11
+
12
+ Add `@mediamonks/react-kit` to your project:
13
+
14
+ ```sh
15
+ npm i @mediamonks/react-kit
16
+ ```
17
+
18
+ ### Example
19
+
20
+ Use a hook inside a component:
21
+
22
+ ```tsx
23
+ import { useToggle } from '@mediamonks/react-kit';
24
+
25
+ function DemoComponent() {
26
+ const [state, toggle] = useToggle(false);
27
+
28
+ return (
29
+ <div>
30
+ <div>{state} </div>
31
+ <button onClick={() => toggle()}>Toggle</button>
32
+ </div>
33
+ );
34
+ }
35
+ ```
36
+
37
+ ## Docs
38
+
39
+ [https://mediamonks.github.io/react-kit/](https://mediamonks.github.io/react-kit/)
40
+
41
+ ## Development
42
+
43
+ The information below should help you develop new hooks in this library.
44
+
45
+ Run `npm run test -- --watch` to run all unit tests in watch mode.
46
+
47
+ Run `npm run storybook` to preview your stories and documentation.
48
+
49
+ ### Folder Structure
50
+
51
+ `useHookName`
52
+
53
+ - `useHookName.ts` – The Hook itself
54
+ - `useHookName.stories.tsx` – To showcase the hook with a working UI, also used for dom testing
55
+ - `useHookName.stories.mdx` – Documentation about the hook
56
+ - `useHookName.test.tsx` – Unit tests for the hook
57
+
58
+ ### Steps for adding a new Hook:
59
+
60
+ Run the `plop` script and enter your hook name starting with `use`.
61
+
62
+ ```shell
63
+ npm run plop
64
+ ```
65
+
66
+ Which will execute the following steps, where you need to fill in the content.
67
+
68
+ - Create a new folder and a new `ts` file with the hook
69
+ - Use the `use` prefix for the name of the hook
70
+ - Use named exports to export the hook
71
+ - Enter JSDoc for description and parameters
72
+ - Re-export the hook in the `index.ts`
73
+ - Add a markdown file documenting the hook
74
+ - General description
75
+ - Reference for types, parameters, return type
76
+ - Simple and extended use cases
77
+ - Add a story file to test out the hook
78
+ - Add an instructions banner at the top of the story
79
+ - Create a type for the StoryArgs that match the template, so it can be used when rendering the
80
+ Story inside tests.
81
+ - Add unit tests for the hook
82
+
83
+ ## Writing Unit test
84
+
85
+ Hooks can be tested using the `renderHook` function that now exists in `@testing-library/react`.
86
+
87
+ At the time of writing, this method is undocumented. It can be used as follows:
88
+
89
+ ```ts
90
+ import { renderHook } from '@testing-library/react';
91
+
92
+ // init the hook
93
+ const { result, rerender, unmount } = renderHook(useToggle, {
94
+ // values passed to your hook
95
+ initialProps: { foo: 'bar' },
96
+ });
97
+
98
+ // inspect the response of the hook
99
+ console.log(result.current);
100
+ ```
101
+
102
+ ### Run Component Lifecycle
103
+
104
+ To interact with your hook, you must use the `act` function.
105
+
106
+ ```ts
107
+ import { act, renderHook } from '@testing-library/react';
108
+
109
+ // init the hook
110
+ const { result, rerender, unmount } = renderHook(useToggle, {
111
+ // values passed to your hook
112
+ initialProps: { foo: 'bar' },
113
+ });
114
+
115
+ // inspect the response of the hook
116
+ console.log(result.current);
117
+
118
+ act(() => {
119
+ // interact with your hook
120
+ result.current[1]();
121
+ });
122
+
123
+ // inspect the updated value of the hook
124
+ console.log(result.current);
125
+ ```
@@ -0,0 +1,21 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * This hook is an internal utility function to visually "log" messages inside your story UI.
4
+ *
5
+ * ```
6
+ * const { getLog, log } = useStorybookLog();
7
+ *
8
+ * return (
9
+ * <div>
10
+ * <div>{getLog()}</div>
11
+ * <button onClick={() => log('clicked')}>Click me</button>
12
+ * </div>
13
+ * )
14
+ * ```
15
+ *
16
+ * @param logRef The Ref that will hold the logs.
17
+ */
18
+ export declare function useStorybookLog(): {
19
+ getLog(): ReactNode;
20
+ log(message: string): void;
21
+ };
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useState } from 'react';
3
+ /**
4
+ * This hook is an internal utility function to visually "log" messages inside your story UI.
5
+ *
6
+ * ```
7
+ * const { getLog, log } = useStorybookLog();
8
+ *
9
+ * return (
10
+ * <div>
11
+ * <div>{getLog()}</div>
12
+ * <button onClick={() => log('clicked')}>Click me</button>
13
+ * </div>
14
+ * )
15
+ * ```
16
+ *
17
+ * @param logRef The Ref that will hold the logs.
18
+ */
19
+ export function useStorybookLog() {
20
+ const [logs, setLogs] = useState([]);
21
+ const log = useCallback((message) => {
22
+ setLogs((oldLogs) => [...oldLogs, message]);
23
+ setTimeout(() => {
24
+ setLogs([]);
25
+ }, 2000);
26
+ }, []);
27
+ const getLog = useCallback(() => (_jsx(_Fragment, { children: logs.map((message) => (_jsx("div", { className: "alert alert-dismissible alert-info", children: message }, message))) })), [logs]);
28
+ return { getLog, log };
29
+ }
@@ -0,0 +1,2 @@
1
+ import { type ReactElement, type ReactFragment } from 'react';
2
+ export declare function childrenAreEqual(previousChildren: ReactElement | ReactFragment | null, nextChildren: ReactElement | ReactFragment | null): boolean;
@@ -0,0 +1,16 @@
1
+ export function childrenAreEqual(previousChildren, nextChildren) {
2
+ if (previousChildren === nextChildren) {
3
+ return true;
4
+ }
5
+ // React reconciler will create a new instance when children type changes
6
+ if ((previousChildren !== null && 'type' in previousChildren && previousChildren.type) !==
7
+ (nextChildren !== null && 'type' in nextChildren && nextChildren.type)) {
8
+ return false;
9
+ }
10
+ // React reconciler will create a new instance when children key changes
11
+ if ((previousChildren !== null && 'key' in previousChildren && previousChildren.key) !==
12
+ (nextChildren !== null && 'key' in nextChildren && nextChildren.key)) {
13
+ return false;
14
+ }
15
+ return true;
16
+ }
@@ -0,0 +1 @@
1
+ export declare function getId(): string;
@@ -0,0 +1,4 @@
1
+ let id = 0;
2
+ export function getId() {
3
+ return (id++ % Number.MAX_SAFE_INTEGER).toString();
4
+ }
@@ -0,0 +1,9 @@
1
+ type UnknownRecord = Record<string | number | symbol, unknown>;
2
+ export type NonNullableRecord<T extends UnknownRecord> = {
3
+ [K in keyof T]: NonNullable<T[K]>;
4
+ };
5
+ /**
6
+ * Check if any value in record is nullable
7
+ */
8
+ export declare function isNonNullableRecord<T extends UnknownRecord>(record: T): record is NonNullableRecord<T>;
9
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Check if any value in record is nullable
3
+ */
4
+ export function isNonNullableRecord(record) {
5
+ return Object.values(record).every((value) => value !== undefined && value !== null);
6
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Trim values from end of array
3
+ */
4
+ export declare function trimEnd<T>(target: Array<T>, value?: T): Array<T>;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Trim values from end of array
3
+ */
4
+ export function trimEnd(target, value) {
5
+ while (target.length > 0 && target.at(-1) === value) {
6
+ target.pop();
7
+ }
8
+ return target;
9
+ }
@@ -0,0 +1,13 @@
1
+ import { type ReactElement, type RefCallback } from 'react';
2
+ type AutoFillChildrenProps = {
3
+ ref: RefCallback<unknown>;
4
+ };
5
+ type AutoFillProps = {
6
+ children: ReactElement<AutoFillChildrenProps> | ReadonlyArray<ReactElement<AutoFillChildrenProps>>;
7
+ axis?: 'x' | 'y';
8
+ };
9
+ /**
10
+ * Repeats children to fill the parent element in given axis.
11
+ */
12
+ export declare function AutoFill({ children, axis }: AutoFillProps): ReactElement;
13
+ export {};
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Children, Fragment, cloneElement, isValidElement, useCallback, useEffect, useRef, useState, } from 'react';
3
+ import { useEventListener } from '../../hooks/useEventListener/useEventListener.js';
4
+ import { useRafCallback } from '../../index.js';
5
+ import { arrayRef } from '../../utils/arrayRef/arrayRef.js';
6
+ /**
7
+ * Repeats children to fill the parent element in given axis.
8
+ */
9
+ export function AutoFill({ children, axis = 'x' }) {
10
+ const childrenRef = useRef([]);
11
+ const [repeatCount, setRepeatCount] = useState(0);
12
+ const updateRepeatCount = useCallback(() => {
13
+ const lastChild = childrenRef.current?.at(-1);
14
+ if (!(lastChild instanceof HTMLElement) || !lastChild.parentElement) {
15
+ return;
16
+ }
17
+ const { offsetTop, offsetLeft, clientWidth, clientHeight, parentElement } = lastChild;
18
+ const { clientWidth: parentClientWidth, clientHeight: parentClientHeight } = parentElement;
19
+ if (axis === 'x') {
20
+ setRepeatCount(Math.ceil(parentClientWidth / (offsetLeft + clientWidth)));
21
+ }
22
+ else {
23
+ setRepeatCount(Math.ceil(parentClientHeight / (offsetTop + clientHeight)));
24
+ }
25
+ }, [axis]);
26
+ useEffect(updateRepeatCount, [updateRepeatCount, children]);
27
+ useEventListener(globalThis.window, 'resize', useRafCallback(updateRepeatCount));
28
+ return (_jsxs(_Fragment, { children: [Children.map(children, (child, index) => isValidElement(child) &&
29
+ cloneElement(child, {
30
+ key: child.key,
31
+ ref: arrayRef(childrenRef, index),
32
+ })), Array.from({ length: repeatCount }, (_, index) => (_jsx(Fragment, { children: children }, index)))] }));
33
+ }
@@ -0,0 +1,11 @@
1
+ declare class AnimationsMap extends Map {
2
+ private readonly callbacks;
3
+ private updateQueued;
4
+ set(key: unknown, value: gsap.core.Animation): this;
5
+ listen(callback: () => void): () => void;
6
+ }
7
+ /**
8
+ * Global map of animations that can be accessed by reference
9
+ */
10
+ export declare const animations: AnimationsMap;
11
+ export {};
@@ -0,0 +1,35 @@
1
+ class AnimationsMap extends Map {
2
+ callbacks = new Set();
3
+ updateQueued = false;
4
+ set(key, value) {
5
+ if (key === null || key === undefined) {
6
+ throw new Error('Cannot set animation with null or undefined key. Make sure the ref you pass correctly has its value set.');
7
+ }
8
+ // skip if value is the same, mostly for optimisation
9
+ if (value === this.get(key)) {
10
+ return this;
11
+ }
12
+ const result = super.set(key, value);
13
+ if (this.updateQueued) {
14
+ return result;
15
+ }
16
+ this.updateQueued = true;
17
+ queueMicrotask(() => {
18
+ for (const callback of this.callbacks) {
19
+ callback();
20
+ }
21
+ this.updateQueued = false;
22
+ });
23
+ return result;
24
+ }
25
+ listen(callback) {
26
+ this.callbacks.add(callback);
27
+ return () => {
28
+ this.callbacks.delete(callback);
29
+ };
30
+ }
31
+ }
32
+ /**
33
+ * Global map of animations that can be accessed by reference
34
+ */
35
+ export const animations = new AnimationsMap();
@@ -0,0 +1,24 @@
1
+ import SplitText from 'gsap/SplitText';
2
+ import { type ComponentProps, type ReactElement, type RefAttributes } from 'react';
3
+ /**
4
+ * Allowed as prop values
5
+ */
6
+ type KnownTarget = Exclude<keyof JSX.IntrinsicElements, symbol | object>;
7
+ type SplitTextWrapperProps<T extends KnownTarget> = {
8
+ /**
9
+ * The SplitText variables
10
+ * @link https://greensock.com/docs/v3/Plugins/SplitText
11
+ */
12
+ variables?: SplitText.Vars;
13
+ /**
14
+ * The element type to render, the default is `div`
15
+ */
16
+ as?: T;
17
+ };
18
+ /**
19
+ * Polymorphic component type, necessary to get all the attributes/props for the
20
+ * as prop component
21
+ */
22
+ type SplitTextWrapperComponent = <T extends KnownTarget = 'div'>(props: SplitTextWrapperProps<T> & Omit<ComponentProps<T>, keyof SplitTextWrapperProps<T> | 'ref'> & RefAttributes<SplitText | null>) => ReactElement;
23
+ export declare const SplitTextWrapper: SplitTextWrapperComponent;
24
+ export {};
@@ -0,0 +1,28 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import gsap from 'gsap';
3
+ import SplitText from 'gsap/SplitText';
4
+ import { renderToString } from 'react-dom/server';
5
+ import { ensuredForwardRef } from '../../../hocs/ensuredForwardRef/ensuredForwardRef.js';
6
+ if (typeof window !== 'undefined') {
7
+ gsap.registerPlugin(SplitText);
8
+ }
9
+ // @ts-expect-error polymorphic type is not compatible with ensuredForwardRef function factory
10
+ export const SplitTextWrapper = ensuredForwardRef(({ variables = {}, as, children, ...props }, ref) => {
11
+ /**
12
+ * Not using useCallback on purpose so that a new SplitText instance is
13
+ * created whenever this component rerenders the children
14
+ */
15
+ const onRef = async (element) => {
16
+ if (ref.current && 'isSplit' in ref.current && ref.current.isSplit) {
17
+ return;
18
+ }
19
+ ref.current = new SplitText(element, variables);
20
+ };
21
+ const Component = (as ?? 'div');
22
+ return (_jsx(Component, { ...props, dangerouslySetInnerHTML: props.dangerouslySetInnerHTML ?? {
23
+ // eslint-disable-next-line @typescript-eslint/naming-convention, react/jsx-no-useless-fragment
24
+ __html: renderToString(_jsx(_Fragment, { children: children })),
25
+ },
26
+ // eslint-disable-next-line react/jsx-no-bind
27
+ ref: onRef }));
28
+ });
@@ -0,0 +1,6 @@
1
+ import { type RefObject } from 'react';
2
+ /**
3
+ * Create gsap animation via a callback, animation is killed when component is
4
+ * unmounted or when a new callback function is provided.
5
+ */
6
+ export declare function useAnimation<T extends gsap.core.Animation | undefined>(callback: () => T, dependencies: ReadonlyArray<unknown>): RefObject<T | undefined>;
@@ -0,0 +1,19 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ /**
3
+ * Create gsap animation via a callback, animation is killed when component is
4
+ * unmounted or when a new callback function is provided.
5
+ */
6
+ export function useAnimation(callback, dependencies) {
7
+ const animation = useRef();
8
+ // eslint-disable-next-line react-hooks/exhaustive-deps, no-underscore-dangle
9
+ const _callback = useCallback(callback, dependencies);
10
+ useEffect(() => {
11
+ // eslint-disable-next-line no-underscore-dangle
12
+ const _animation = _callback();
13
+ animation.current = _animation;
14
+ return () => {
15
+ _animation?.kill();
16
+ };
17
+ }, [_callback]);
18
+ return animation;
19
+ }
@@ -0,0 +1,6 @@
1
+ import { type RefObject } from 'react';
2
+ import { type Unreffable } from '../../../utils/unref/unref.js';
3
+ /**
4
+ * Hook to store animation using a reference in global animations map
5
+ */
6
+ export declare function useExposeAnimation(animation: RefObject<gsap.core.Animation | undefined>, reference: Unreffable<unknown>): void;
@@ -0,0 +1,28 @@
1
+ import { useEffect } from 'react';
2
+ import { unref } from '../../../utils/unref/unref.js';
3
+ import { animations } from '../../animations.js';
4
+ /**
5
+ * Hook to store animation using a reference in global animations map
6
+ */
7
+ export function useExposeAnimation(animation, reference) {
8
+ useEffect(() => {
9
+ // eslint-disable-next-line no-underscore-dangle
10
+ const _reference = unref(reference);
11
+ // eslint-disable-next-line no-underscore-dangle
12
+ const _animation = animation.current;
13
+ if (_animation && _reference) {
14
+ animations.set(_reference, _animation);
15
+ }
16
+ return () => {
17
+ animations.delete(_reference);
18
+ };
19
+ // TODO: We currently rely on the Component where this hook is used,
20
+ // and we know that animation will get a new ref.current assigned
21
+ // as part of useAnimation, if that has dependencies.
22
+ // If that updates (due to a re-render), we should also update
23
+ // the animation in the global map.
24
+ // This feels a bit flaky, but I can't think of a better way to do this currently.
25
+ // We should probably have these hooks more integrated with each other.
26
+ // eslint-disable-next-line react-hooks/exhaustive-deps
27
+ }, [animation, animation.current, reference]);
28
+ }
@@ -0,0 +1,5 @@
1
+ import { type Unreffable } from '../../../index.js';
2
+ /**
3
+ * Hook to get animation from global animations map using given reference
4
+ */
5
+ export declare function useExposedAnimation<T extends gsap.core.Animation>(target: Unreffable<unknown>): T | undefined;
@@ -0,0 +1,13 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { unref } from '../../../index.js';
3
+ import { animations } from '../../animations.js';
4
+ /**
5
+ * Hook to get animation from global animations map using given reference
6
+ */
7
+ export function useExposedAnimation(target) {
8
+ const [animation, setAnimation] = useState();
9
+ useEffect(() => animations.listen(() => {
10
+ setAnimation(animations.get(unref(target)));
11
+ }), [target]);
12
+ return animation;
13
+ }
@@ -0,0 +1,5 @@
1
+ import { type Unreffable } from '../../../index.js';
2
+ /**
3
+ * Hook to get animation from global animations map using given reference
4
+ */
5
+ export declare function useExposedAnimations(target: Unreffable<ReadonlyArray<unknown>>): ReadonlyArray<gsap.core.Animation>;
@@ -0,0 +1,32 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { unref } from '../../../index.js';
3
+ import { animations } from '../../animations.js';
4
+ /**
5
+ * Hook to get animation from global animations map using given reference
6
+ */
7
+ export function useExposedAnimations(target) {
8
+ const [exposedAnimations, setExposedAnimations] = useState([]);
9
+ useEffect(() => animations.listen(() => {
10
+ const array = unref(target);
11
+ if (array) {
12
+ const newAnimations = array.map((ref) => animations.get(ref));
13
+ // this should only be done when the refs have been updated, otherwise we're returning
14
+ // a new array ref with the same values, which will cause a re-render
15
+ setExposedAnimations((currentAnimations) => areArraysEqual(newAnimations, currentAnimations) ? currentAnimations : newAnimations);
16
+ }
17
+ }),
18
+ // eslint-disable-next-line react-hooks/exhaustive-deps
19
+ [target]);
20
+ return exposedAnimations;
21
+ }
22
+ function areArraysEqual(a, b) {
23
+ if (a.length !== b.length) {
24
+ return false;
25
+ }
26
+ for (const [index, element] of a.entries()) {
27
+ if (element !== b[index]) {
28
+ return false;
29
+ }
30
+ }
31
+ return true;
32
+ }
@@ -0,0 +1,3 @@
1
+ import { type MutableRefObject } from 'react';
2
+ import { type Unreffable } from '../../../utils/unref/unref.js';
3
+ export declare function useFlip(ref: Unreffable<HTMLElement | null>, flipStateVariables?: Flip.FromToVars): MutableRefObject<Flip.FlipState | undefined>;
@@ -0,0 +1,18 @@
1
+ import gsap from 'gsap';
2
+ import Flip from 'gsap/Flip';
3
+ import { useEffect, useRef } from 'react';
4
+ import { unref } from '../../../utils/unref/unref.js';
5
+ gsap.registerPlugin(Flip);
6
+ export function useFlip(ref, flipStateVariables = {}) {
7
+ const flipStateRef = useRef();
8
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
9
+ if (globalThis.window !== undefined) {
10
+ flipStateRef.current = Flip.getState(unref(ref));
11
+ }
12
+ useEffect(() => {
13
+ if (flipStateRef.current) {
14
+ Flip.from(flipStateRef.current, flipStateVariables);
15
+ }
16
+ });
17
+ return flipStateRef;
18
+ }
@@ -0,0 +1,9 @@
1
+ import { type RefObject } from 'react';
2
+ /**
3
+ * Hook to create animation that make use of ScrollTrigger, ScrollTrigger is refreshed
4
+ * when the global animations map is updated.
5
+ *
6
+ * Note: do not scrub a React component's root because React won't know what element to
7
+ * unmount when the component with a pinned animation is removed from the vDOM.
8
+ */
9
+ export declare function useScrollAnimation<T extends gsap.core.Animation>(callback: () => T | undefined, dependencies: ReadonlyArray<unknown>): RefObject<T | undefined>;
@@ -0,0 +1,26 @@
1
+ import gsap from 'gsap';
2
+ import ScrollTrigger from 'gsap/ScrollTrigger';
3
+ import { useEffect, useRef } from 'react';
4
+ import { animations } from '../../animations.js';
5
+ import { useAnimation } from '../useAnimation/useAnimation.js';
6
+ import { useExposeAnimation } from '../useExposeAnimation/useExposeAnimation.js';
7
+ if (typeof window !== 'undefined') {
8
+ gsap.registerPlugin(ScrollTrigger);
9
+ }
10
+ /**
11
+ * Hook to create animation that make use of ScrollTrigger, ScrollTrigger is refreshed
12
+ * when the global animations map is updated.
13
+ *
14
+ * Note: do not scrub a React component's root because React won't know what element to
15
+ * unmount when the component with a pinned animation is removed from the vDOM.
16
+ */
17
+ export function useScrollAnimation(callback, dependencies) {
18
+ const animation = useAnimation(callback, dependencies);
19
+ // Expose animation so that we can leverage the listener from the global animations map
20
+ const ref = useRef(Symbol('useScrollAnimation'));
21
+ useExposeAnimation(animation, ref);
22
+ useEffect(() => animations.listen(() => {
23
+ ScrollTrigger.refresh();
24
+ }), []);
25
+ return animation;
26
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Tries to get animation from global animations map for given reference
3
+ */
4
+ export declare function getAnimation(reference: unknown): gsap.core.Animation | undefined;
@@ -0,0 +1,7 @@
1
+ import { animations } from '../../animations.js';
2
+ /**
3
+ * Tries to get animation from global animations map for given reference
4
+ */
5
+ export function getAnimation(reference) {
6
+ return animations.get(reference);
7
+ }
@@ -0,0 +1,11 @@
1
+ import { type ForwardRefExoticComponent, type MutableRefObject, type PropsWithoutRef, type ReactElement, type RefAttributes } from 'react';
2
+ export interface EnsuredForwardRefRenderFunction<T, P = Record<string | number | symbol, unknown>> {
3
+ (props: P, ref: MutableRefObject<T | null>): ReactElement | null;
4
+ displayName?: string | undefined;
5
+ /**
6
+ * defaultProps are not supported on render functions
7
+ */
8
+ defaultProps?: never;
9
+ propTypes?: never;
10
+ }
11
+ export declare function ensuredForwardRef<T, P = Record<string | number | symbol, unknown>>(Component: EnsuredForwardRefRenderFunction<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;