@mediamonks/react-kit 1.0.0 → 1.0.2

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.
@@ -0,0 +1,9 @@
1
+ import { type ComponentProps, type ReactNode } from 'react';
2
+ type AutoAdjustFontSizeProps = ComponentProps<'div'> & {
3
+ children: ReactNode;
4
+ minFontSize?: number;
5
+ maxFontSize?: number;
6
+ axis?: 'x' | 'y';
7
+ };
8
+ export declare const AutoAdjustFontSize: import("react").ForwardRefExoticComponent<Omit<AutoAdjustFontSizeProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
9
+ export {};
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { ensuredForwardRef } from '../../hocs/ensuredForwardRef/ensuredForwardRef.js';
4
+ import { useResizeObserver } from '../../hooks/useResizeObserver/useResizeObserver.js';
5
+ import { adjustFontSize } from '../../utils/adjustFontSize/adjustFontSize.js';
6
+ export const AutoAdjustFontSize = ensuredForwardRef(({ children, minFontSize, maxFontSize, axis, style }, ref) => {
7
+ const [parentElement, setParentElement] = useState(null);
8
+ const updateFontSize = useCallback(() => {
9
+ if (!ref.current) {
10
+ return;
11
+ }
12
+ adjustFontSize(ref.current, minFontSize, maxFontSize, axis);
13
+ }, [axis, maxFontSize, minFontSize, ref]);
14
+ useEffect(() => {
15
+ if (!ref.current) {
16
+ return;
17
+ }
18
+ setParentElement(ref.current.parentElement);
19
+ updateFontSize();
20
+ ref.current.style.visibility = 'visible';
21
+ }, [ref, updateFontSize]);
22
+ useResizeObserver(parentElement, updateFontSize);
23
+ return (_jsx("div", { ref: ref, style: {
24
+ whiteSpace: 'nowrap',
25
+ inlineSize: 'max-content',
26
+ blockSize: 'max-content',
27
+ visibility: 'hidden',
28
+ ...style,
29
+ }, children: children }));
30
+ });
@@ -2,7 +2,9 @@ import gsap from 'gsap';
2
2
  import Flip from 'gsap/Flip';
3
3
  import { useEffect, useRef } from 'react';
4
4
  import { unref } from '../../../utils/unref/unref.js';
5
- gsap.registerPlugin(Flip);
5
+ if (typeof window !== 'undefined') {
6
+ gsap.registerPlugin(Flip);
7
+ }
6
8
  export function useFlip(ref, flipStateVariables = {}) {
7
9
  const flipStateRef = useRef();
8
10
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -0,0 +1,7 @@
1
+ import { type RefObject } from 'react';
2
+ import { type Unreffable } from '../../utils/unref/unref.js';
3
+ /**
4
+ * A hook that returns a ref object containing the content rectangle of the target
5
+ * element. The content rectangle is updated whenever the target element is resized.
6
+ */
7
+ export declare function useContentRect(target: Unreffable<Element | null>): RefObject<DOMRectReadOnly | null>;
@@ -0,0 +1,18 @@
1
+ import { useRef } from 'react';
2
+ import { useMount } from '../../lifecycle/hooks/useMount/useMount.js';
3
+ import { unref } from '../../utils/unref/unref.js';
4
+ import { useResizeObserver } from '../useResizeObserver/useResizeObserver.js';
5
+ /**
6
+ * A hook that returns a ref object containing the content rectangle of the target
7
+ * element. The content rectangle is updated whenever the target element is resized.
8
+ */
9
+ export function useContentRect(target) {
10
+ const contentRectRef = useRef(null);
11
+ useResizeObserver(target, (entries) => {
12
+ contentRectRef.current = entries.at(0)?.contentRect ?? null;
13
+ });
14
+ useMount(() => {
15
+ contentRectRef.current = unref(target)?.getBoundingClientRect() ?? null;
16
+ });
17
+ return contentRectRef;
18
+ }
@@ -0,0 +1,6 @@
1
+ import { type Unreffable } from '../../utils/unref/unref.js';
2
+ /**
3
+ * A hook that returns the content rectangle of the target element.
4
+ * The content rectangle is updated whenever the target element is resized.
5
+ */
6
+ export declare function useContentRectState(target: Unreffable<Element | null>): DOMRectReadOnly | null;
@@ -0,0 +1,22 @@
1
+ import { useRef, useState } from 'react';
2
+ import { useMount } from '../../index.js';
3
+ import { unref } from '../../utils/unref/unref.js';
4
+ import { useResizeObserver } from '../useResizeObserver/useResizeObserver.js';
5
+ /**
6
+ * A hook that returns the content rectangle of the target element.
7
+ * The content rectangle is updated whenever the target element is resized.
8
+ */
9
+ export function useContentRectState(target) {
10
+ const [contentRect, setContentRect] = useState(null);
11
+ const rafRef = useRef(0);
12
+ useResizeObserver(target, (entries) => {
13
+ cancelAnimationFrame(rafRef.current);
14
+ rafRef.current = requestAnimationFrame(() => {
15
+ setContentRect(entries.at(0)?.contentRect ?? null);
16
+ });
17
+ });
18
+ useMount(() => {
19
+ setContentRect(unref(target)?.getBoundingClientRect() ?? null);
20
+ });
21
+ return contentRect;
22
+ }
@@ -5,5 +5,6 @@ import { type Unreffable } from '../../utils/unref/unref.js';
5
5
  *
6
6
  * @param target - The target to observe
7
7
  * @param callback - The callback to fire when the element resizes
8
+ * @param options - The ResizeObserverOptions for the observed element
8
9
  */
9
- export declare function useResizeObserver(target: Unreffable<Element | null>, callback: ResizeObserverCallback): void;
10
+ export declare function useResizeObserver(target: Unreffable<Element | null>, callback?: ResizeObserverCallback | undefined, options?: ResizeObserverOptions): void;
@@ -6,17 +6,19 @@ import { unref } from '../../utils/unref/unref.js';
6
6
  *
7
7
  * @param target - The target to observe
8
8
  * @param callback - The callback to fire when the element resizes
9
+ * @param options - The ResizeObserverOptions for the observed element
9
10
  */
10
- export function useResizeObserver(target, callback) {
11
+ export function useResizeObserver(target, callback, options) {
11
12
  useEffect(() => {
12
13
  const element = unref(target);
13
- if (element === null) {
14
+ if (element === null || callback === undefined) {
14
15
  return;
15
16
  }
16
- const resizeObserverInstance = new ResizeObserver(callback);
17
- resizeObserverInstance.observe(element);
17
+ const resizeObserver = new ResizeObserver(callback);
18
+ resizeObserver.observe(element, options);
18
19
  return () => {
19
- resizeObserverInstance.disconnect();
20
+ resizeObserver.disconnect();
20
21
  };
21
- }, [target, callback]);
22
+ // eslint-disable-next-line react-hooks/exhaustive-deps
23
+ }, [target, callback, ...Object.values(options ?? {})]);
22
24
  }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './components/AutoAdjustFontSize/AutoAdjustFontSize.js';
1
2
  export * from './components/AutoFill/AutoFill.js';
2
3
  export * from './gsap/components/SplitTextWrapper/SplitTextWrapper.js';
3
4
  export * from './gsap/hooks/useAnimation/useAnimation.js';
@@ -9,6 +10,8 @@ export * from './gsap/hooks/useScrollAnimation/useScrollAnimation.js';
9
10
  export * from './gsap/utils/getAnimation/getAnimation.js';
10
11
  export * from './hocs/ensuredForwardRef/ensuredForwardRef.js';
11
12
  export * from './hooks/useClientSideValue/useClientSideValue.js';
13
+ export * from './hooks/useContentRect/useContentRect.js';
14
+ export * from './hooks/useContentRectState/useContentRectState.js';
12
15
  export * from './hooks/useEventListener/useEventListener.js';
13
16
  export * from './hooks/useForceRerender/useForceRerender.js';
14
17
  export * from './hooks/useHasFocus/useHasFocus.js';
@@ -34,6 +37,7 @@ export * from './lifecycle/hooks/useIsMountedState/useIsMountedState.js';
34
37
  export * from './lifecycle/hooks/useMount/useMount.js';
35
38
  export * from './lifecycle/hooks/useUnmount/useUnmount.js';
36
39
  export * from './nextjs/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js';
40
+ export * from './utils/adjustFontSize/adjustFontSize.js';
37
41
  export * from './utils/arrayRef/arrayRef.js';
38
42
  export * from './utils/createTimeout/createTimeout.js';
39
43
  export * from './utils/isRefObject/isRefObject.js';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  /* PLOP_ADD_EXPORT */
2
+ export * from './components/AutoAdjustFontSize/AutoAdjustFontSize.js';
2
3
  export * from './components/AutoFill/AutoFill.js';
3
4
  export * from './gsap/components/SplitTextWrapper/SplitTextWrapper.js';
4
5
  export * from './gsap/hooks/useAnimation/useAnimation.js';
@@ -10,6 +11,8 @@ export * from './gsap/hooks/useScrollAnimation/useScrollAnimation.js';
10
11
  export * from './gsap/utils/getAnimation/getAnimation.js';
11
12
  export * from './hocs/ensuredForwardRef/ensuredForwardRef.js';
12
13
  export * from './hooks/useClientSideValue/useClientSideValue.js';
14
+ export * from './hooks/useContentRect/useContentRect.js';
15
+ export * from './hooks/useContentRectState/useContentRectState.js';
13
16
  export * from './hooks/useEventListener/useEventListener.js';
14
17
  export * from './hooks/useForceRerender/useForceRerender.js';
15
18
  export * from './hooks/useHasFocus/useHasFocus.js';
@@ -35,6 +38,7 @@ export * from './lifecycle/hooks/useIsMountedState/useIsMountedState.js';
35
38
  export * from './lifecycle/hooks/useMount/useMount.js';
36
39
  export * from './lifecycle/hooks/useUnmount/useUnmount.js';
37
40
  export * from './nextjs/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js';
41
+ export * from './utils/adjustFontSize/adjustFontSize.js';
38
42
  export * from './utils/arrayRef/arrayRef.js';
39
43
  export * from './utils/createTimeout/createTimeout.js';
40
44
  export * from './utils/isRefObject/isRefObject.js';
@@ -3,10 +3,12 @@
3
3
  * @param callbackFunction function to be called when the component is mounted
4
4
  *
5
5
  * @example
6
- * ```
7
6
  * useMount(() => {
8
7
  * console.log('component is mounted');
9
8
  * })
10
- * ```
9
+ *
10
+ * useMount(async () => {
11
+ * console.log('component is mounted');
12
+ * })
11
13
  */
12
- export declare function useMount(callbackFunction: () => void): void;
14
+ export declare function useMount(callbackFunction: () => void | PromiseLike<void>): void;
@@ -4,13 +4,18 @@ import { useEffect } from 'react';
4
4
  * @param callbackFunction function to be called when the component is mounted
5
5
  *
6
6
  * @example
7
- * ```
8
7
  * useMount(() => {
9
8
  * console.log('component is mounted');
10
9
  * })
11
- * ```
10
+ *
11
+ * useMount(async () => {
12
+ * console.log('component is mounted');
13
+ * })
12
14
  */
13
15
  export function useMount(callbackFunction) {
16
+ useEffect(() => {
17
+ callbackFunction();
18
+ },
14
19
  // eslint-disable-next-line react-hooks/exhaustive-deps
15
- useEffect(callbackFunction, []);
20
+ []);
16
21
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Adjusts the font size of an HTML element to fit within its parent container.
3
+ *
4
+ * @param element - The HTML element whose font size needs to be adjusted.
5
+ * @param minFontSize - The minimum font size in pixels. Default is 13 (minimal accessible font size).
6
+ * @param maxFontSize - The maximum font size in pixels.
7
+ * @param axis - The axis along which the font size should be adjusted. Can be 'x' or 'y'. Default is undefined (both axes).
8
+ *
9
+ * @throws {TypeError} If the parent element is null or if minFontSize is greater than maxFontSize.
10
+ */
11
+ export declare function adjustFontSize(element: HTMLElement, minFontSize?: number, maxFontSize?: number, axis?: 'x' | 'y'): void;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Adjusts the font size of an HTML element to fit within its parent container.
3
+ *
4
+ * @param element - The HTML element whose font size needs to be adjusted.
5
+ * @param minFontSize - The minimum font size in pixels. Default is 13 (minimal accessible font size).
6
+ * @param maxFontSize - The maximum font size in pixels.
7
+ * @param axis - The axis along which the font size should be adjusted. Can be 'x' or 'y'. Default is undefined (both axes).
8
+ *
9
+ * @throws {TypeError} If the parent element is null or if minFontSize is greater than maxFontSize.
10
+ */
11
+ export function adjustFontSize(element,
12
+ // eslint-disable-next-line default-param-last
13
+ minFontSize = 13,
14
+ // eslint-disable-next-line default-param-last
15
+ maxFontSize, axis) {
16
+ if (maxFontSize && minFontSize > maxFontSize) {
17
+ throw new TypeError('minFontSize is greater than maxFontSize');
18
+ }
19
+ if (element.parentElement === null) {
20
+ throw new TypeError('Parent element is null');
21
+ }
22
+ // minimum font size in pixels
23
+ let min = minFontSize;
24
+ // maximum font size in pixels
25
+ let max = maxFontSize ?? Math.max(element.parentElement.clientWidth, element.parentElement.clientHeight);
26
+ let lastGoodFontSize;
27
+ while (min <= max) {
28
+ const mid = Math.floor((min + max) / 2);
29
+ element.style.fontSize = `${mid}px`;
30
+ const { width: elementWidthAfterLayout, height: elementHeightAfterLayout } = element.getBoundingClientRect();
31
+ const { width: parentElementWidthAfterLayout, height: parentElementHeightAfterLayout } = element.parentElement.getBoundingClientRect();
32
+ const exceedsWidth = axis !== 'y' && elementWidthAfterLayout > parentElementWidthAfterLayout;
33
+ const exceedsHeight = axis !== 'x' && elementHeightAfterLayout > parentElementHeightAfterLayout;
34
+ if (exceedsWidth || exceedsHeight) {
35
+ // If the text is too wide/tall, decrease the font size
36
+ max = mid - 1;
37
+ }
38
+ else {
39
+ // If the text fits, increase the font size
40
+ lastGoodFontSize = mid;
41
+ min = mid + 1;
42
+ }
43
+ }
44
+ element.style.fontSize = `${lastGoodFontSize}px`;
45
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mediamonks/react-kit",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "A collection of React hooks, components, utilities that we use at Media.Monks",
5
5
  "keywords": [
6
6
  "react",
@@ -8,7 +8,10 @@
8
8
  "typescript",
9
9
  "hooks"
10
10
  ],
11
- "repository": "git@github.com:mediamonks/react-kit.git",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+ssh://git@github.com/mediamonks/react-kit.git"
14
+ },
12
15
  "author": "frontend.monks",
13
16
  "license": "MIT",
14
17
  "types": "./dist/index.d.ts",