react-essentials-functions 1.0.2 → 1.1.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.
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useDebounce = useDebounce;
4
+ const react_1 = require("react");
5
+ /**
6
+ * Hook that debounces a value by a given delay.
7
+ * The debounced value will only update after the specified delay has passed
8
+ * since the last change.
9
+ *
10
+ * @param value - The value to debounce
11
+ * @param delay - The debounce delay in milliseconds
12
+ * @returns The debounced value
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * const [searchTerm, setSearchTerm] = useState('');
17
+ * const debouncedSearch = useDebounce(searchTerm, 300);
18
+ *
19
+ * useEffect(() => {
20
+ * // This will only fire 300ms after the user stops typing
21
+ * fetchResults(debouncedSearch);
22
+ * }, [debouncedSearch]);
23
+ * ```
24
+ */
25
+ function useDebounce(value, delay) {
26
+ const [debouncedValue, setDebouncedValue] = (0, react_1.useState)(value);
27
+ (0, react_1.useEffect)(() => {
28
+ const handler = setTimeout(() => {
29
+ setDebouncedValue(value);
30
+ }, delay);
31
+ return () => {
32
+ clearTimeout(handler);
33
+ };
34
+ }, [value, delay]);
35
+ return debouncedValue;
36
+ }
@@ -1,5 +1,25 @@
1
- import React from 'react';
2
- export declare function useDimensions(targetRef: React.RefObject<HTMLElement>): {
1
+ import { RefObject } from 'react';
2
+ export type Dimensions = {
3
3
  width: number;
4
4
  height: number;
5
5
  };
6
+ /**
7
+ * Hook to get the dimensions of a DOM element.
8
+ * Uses ResizeObserver for optimal performance.
9
+ *
10
+ * @param targetRef - React ref to the element to measure
11
+ * @returns Object containing width and height of the element
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * const targetRef = useRef<HTMLDivElement>(null);
16
+ * const { width, height } = useDimensions(targetRef);
17
+ *
18
+ * return (
19
+ * <div ref={targetRef}>
20
+ * Size: {width} x {height}
21
+ * </div>
22
+ * );
23
+ * ```
24
+ */
25
+ export declare function useDimensions(targetRef: RefObject<HTMLElement>): Dimensions;
@@ -1,35 +1,71 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useDimensions = void 0;
3
+ exports.useDimensions = useDimensions;
4
4
  const react_1 = require("react");
5
+ /**
6
+ * Hook to get the dimensions of a DOM element.
7
+ * Uses ResizeObserver for optimal performance.
8
+ *
9
+ * @param targetRef - React ref to the element to measure
10
+ * @returns Object containing width and height of the element
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * const targetRef = useRef<HTMLDivElement>(null);
15
+ * const { width, height } = useDimensions(targetRef);
16
+ *
17
+ * return (
18
+ * <div ref={targetRef}>
19
+ * Size: {width} x {height}
20
+ * </div>
21
+ * );
22
+ * ```
23
+ */
5
24
  function useDimensions(targetRef) {
6
- const getDimensions = () => {
25
+ const getDimensions = (0, react_1.useCallback)(() => {
7
26
  return {
8
27
  width: targetRef.current ? targetRef.current.offsetWidth : 0,
9
28
  height: targetRef.current ? targetRef.current.offsetHeight : 0,
10
29
  };
11
- };
12
- const [dimensions, setDimensions] = (0, react_1.useState)(getDimensions);
13
- const handleResize = () => {
14
- setDimensions(getDimensions());
15
- };
30
+ // targetRef is a ref object - stable across renders, no need in deps
31
+ // eslint-disable-next-line react-hooks/exhaustive-deps
32
+ }, []);
33
+ const [dimensions, setDimensions] = (0, react_1.useState)({
34
+ width: 0,
35
+ height: 0,
36
+ });
37
+ (0, react_1.useLayoutEffect)(() => {
38
+ if (targetRef.current) {
39
+ setDimensions(getDimensions());
40
+ }
41
+ // eslint-disable-next-line react-hooks/exhaustive-deps
42
+ }, []);
16
43
  (0, react_1.useEffect)(() => {
44
+ const element = targetRef.current;
45
+ if (!element) {
46
+ return;
47
+ }
48
+ // Use ResizeObserver for better performance than window resize events
49
+ if (typeof ResizeObserver !== 'undefined') {
50
+ const resizeObserver = new ResizeObserver(() => {
51
+ setDimensions(getDimensions());
52
+ });
53
+ resizeObserver.observe(element);
54
+ return () => {
55
+ resizeObserver.disconnect();
56
+ };
57
+ }
58
+ // Fallback for browsers that don't support ResizeObserver
59
+ const handleResize = () => {
60
+ setDimensions(getDimensions());
61
+ };
17
62
  window.addEventListener('resize', handleResize);
18
63
  window.addEventListener('scroll', handleResize);
19
- window.addEventListener('load', handleResize);
20
64
  return () => {
21
65
  window.removeEventListener('resize', handleResize);
22
66
  window.removeEventListener('scroll', handleResize);
23
- window.addEventListener('load', handleResize);
24
67
  };
25
- }, []);
26
- (0, react_1.useLayoutEffect)(() => {
27
- handleResize();
68
+ // eslint-disable-next-line react-hooks/exhaustive-deps
28
69
  }, []);
29
70
  return dimensions;
30
71
  }
31
- exports.useDimensions = useDimensions;
32
- // const targetRef = useRef() // then set a ref to your component
33
- // const size = useDimensions(targetRef)
34
- // ....
35
- // return (div ref={targetRef}> .... <p>{size.width} - {size.height} </p> .... </div>);
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Hook that syncs state with localStorage.
3
+ * Handles serialization/deserialization automatically with JSON.
4
+ * Falls back gracefully when localStorage is unavailable.
5
+ *
6
+ * @param key - The localStorage key
7
+ * @param initialValue - The initial value if nothing is stored
8
+ * @returns A tuple of [storedValue, setValue, removeValue]
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * const [name, setName, removeName] = useLocalStorage('user-name', '');
13
+ *
14
+ * return (
15
+ * <input
16
+ * value={name}
17
+ * onChange={(e) => setName(e.target.value)}
18
+ * />
19
+ * );
20
+ * ```
21
+ */
22
+ export declare function useLocalStorage<T>(key: string, initialValue: T): [T, (value: T | ((prev: T) => T)) => void, () => void];
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useLocalStorage = useLocalStorage;
4
+ const react_1 = require("react");
5
+ /**
6
+ * Hook that syncs state with localStorage.
7
+ * Handles serialization/deserialization automatically with JSON.
8
+ * Falls back gracefully when localStorage is unavailable.
9
+ *
10
+ * @param key - The localStorage key
11
+ * @param initialValue - The initial value if nothing is stored
12
+ * @returns A tuple of [storedValue, setValue, removeValue]
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * const [name, setName, removeName] = useLocalStorage('user-name', '');
17
+ *
18
+ * return (
19
+ * <input
20
+ * value={name}
21
+ * onChange={(e) => setName(e.target.value)}
22
+ * />
23
+ * );
24
+ * ```
25
+ */
26
+ function useLocalStorage(key, initialValue) {
27
+ const [storedValue, setStoredValue] = (0, react_1.useState)(() => {
28
+ if (typeof window === 'undefined') {
29
+ return initialValue;
30
+ }
31
+ try {
32
+ const item = window.localStorage.getItem(key);
33
+ return item !== null ? JSON.parse(item) : initialValue;
34
+ }
35
+ catch {
36
+ return initialValue;
37
+ }
38
+ });
39
+ const setValue = (0, react_1.useCallback)((value) => {
40
+ setStoredValue((prev) => {
41
+ const valueToStore = value instanceof Function ? value(prev) : value;
42
+ try {
43
+ window.localStorage.setItem(key, JSON.stringify(valueToStore));
44
+ }
45
+ catch {
46
+ // localStorage may not be available
47
+ }
48
+ return valueToStore;
49
+ });
50
+ }, [key]);
51
+ const removeValue = (0, react_1.useCallback)(() => {
52
+ try {
53
+ window.localStorage.removeItem(key);
54
+ }
55
+ catch {
56
+ // localStorage may not be available
57
+ }
58
+ setStoredValue(initialValue);
59
+ }, [key, initialValue]);
60
+ return [storedValue, setValue, removeValue];
61
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Hook that tracks whether a CSS media query matches.
3
+ * Listens for changes and updates automatically.
4
+ *
5
+ * @param query - The CSS media query string (e.g. '(min-width: 768px)')
6
+ * @returns Whether the media query currently matches
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const isMobile = useMediaQuery('(max-width: 767px)');
11
+ * const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');
12
+ * const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');
13
+ *
14
+ * return isMobile ? <MobileLayout /> : <DesktopLayout />;
15
+ * ```
16
+ */
17
+ export declare function useMediaQuery(query: string): boolean;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useMediaQuery = useMediaQuery;
4
+ const react_1 = require("react");
5
+ /**
6
+ * Hook that tracks whether a CSS media query matches.
7
+ * Listens for changes and updates automatically.
8
+ *
9
+ * @param query - The CSS media query string (e.g. '(min-width: 768px)')
10
+ * @returns Whether the media query currently matches
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * const isMobile = useMediaQuery('(max-width: 767px)');
15
+ * const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');
16
+ * const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');
17
+ *
18
+ * return isMobile ? <MobileLayout /> : <DesktopLayout />;
19
+ * ```
20
+ */
21
+ function useMediaQuery(query) {
22
+ const [matches, setMatches] = (0, react_1.useState)(() => {
23
+ if (typeof window === 'undefined') {
24
+ return false;
25
+ }
26
+ return window.matchMedia(query).matches;
27
+ });
28
+ (0, react_1.useEffect)(() => {
29
+ if (typeof window === 'undefined') {
30
+ return;
31
+ }
32
+ const mediaQuery = window.matchMedia(query);
33
+ setMatches(mediaQuery.matches);
34
+ const handleChange = (event) => {
35
+ setMatches(event.matches);
36
+ };
37
+ mediaQuery.addEventListener('change', handleChange);
38
+ return () => {
39
+ mediaQuery.removeEventListener('change', handleChange);
40
+ };
41
+ }, [query]);
42
+ return matches;
43
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Hook that returns the previous value of a variable.
3
+ * Useful for comparing current and previous props or state.
4
+ *
5
+ * @param value - The value to track
6
+ * @returns The value from the previous render, or undefined on first render
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const [count, setCount] = useState(0);
11
+ * const previousCount = usePrevious(count);
12
+ *
13
+ * return (
14
+ * <div>
15
+ * Current: {count}, Previous: {previousCount ?? 'N/A'}
16
+ * </div>
17
+ * );
18
+ * ```
19
+ */
20
+ export declare function usePrevious<T>(value: T): T | undefined;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePrevious = usePrevious;
4
+ const react_1 = require("react");
5
+ /**
6
+ * Hook that returns the previous value of a variable.
7
+ * Useful for comparing current and previous props or state.
8
+ *
9
+ * @param value - The value to track
10
+ * @returns The value from the previous render, or undefined on first render
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * const [count, setCount] = useState(0);
15
+ * const previousCount = usePrevious(count);
16
+ *
17
+ * return (
18
+ * <div>
19
+ * Current: {count}, Previous: {previousCount ?? 'N/A'}
20
+ * </div>
21
+ * );
22
+ * ```
23
+ */
24
+ function usePrevious(value) {
25
+ const ref = (0, react_1.useRef)(undefined);
26
+ (0, react_1.useEffect)(() => {
27
+ ref.current = value;
28
+ }, [value]);
29
+ return ref.current;
30
+ }
@@ -1 +1,26 @@
1
- export declare function useSafeFetch(): (url: string, options: Record<any, any>) => Promise<Response>;
1
+ /**
2
+ * Hook that provides a fetch function which automatically aborts previous
3
+ * requests and cleans up on unmount using AbortController.
4
+ *
5
+ * @returns A fetch function with automatic abort handling
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * const safeFetch = useSafeFetch();
10
+ *
11
+ * useEffect(() => {
12
+ * const fetchData = async () => {
13
+ * try {
14
+ * const response = await safeFetch('https://api.example.com/data');
15
+ * const data = await response.json();
16
+ * } catch (error) {
17
+ * if (error.name !== 'AbortError') {
18
+ * console.error('Fetch error:', error);
19
+ * }
20
+ * }
21
+ * };
22
+ * fetchData();
23
+ * }, [safeFetch]);
24
+ * ```
25
+ */
26
+ export declare function useSafeFetch(): (url: string, options?: RequestInit) => Promise<Response>;
@@ -1,10 +1,48 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useSafeFetch = void 0;
3
+ exports.useSafeFetch = useSafeFetch;
4
4
  const react_1 = require("react");
5
+ /**
6
+ * Hook that provides a fetch function which automatically aborts previous
7
+ * requests and cleans up on unmount using AbortController.
8
+ *
9
+ * @returns A fetch function with automatic abort handling
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * const safeFetch = useSafeFetch();
14
+ *
15
+ * useEffect(() => {
16
+ * const fetchData = async () => {
17
+ * try {
18
+ * const response = await safeFetch('https://api.example.com/data');
19
+ * const data = await response.json();
20
+ * } catch (error) {
21
+ * if (error.name !== 'AbortError') {
22
+ * console.error('Fetch error:', error);
23
+ * }
24
+ * }
25
+ * };
26
+ * fetchData();
27
+ * }, [safeFetch]);
28
+ * ```
29
+ */
5
30
  function useSafeFetch() {
6
- const abortController = (0, react_1.useRef)(new AbortController());
7
- (0, react_1.useEffect)(() => () => abortController.current.abort(), []);
8
- return (0, react_1.useCallback)((url, options) => fetch(url, { signal: abortController.current.signal, ...options }), []);
31
+ const abortControllerRef = (0, react_1.useRef)(null);
32
+ (0, react_1.useEffect)(() => {
33
+ return () => {
34
+ abortControllerRef.current?.abort();
35
+ };
36
+ }, []);
37
+ return (0, react_1.useCallback)((url, options = {}) => {
38
+ abortControllerRef.current?.abort();
39
+ const abortController = new AbortController();
40
+ abortControllerRef.current = abortController;
41
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
42
+ const { signal, ...restOptions } = options;
43
+ return fetch(url, {
44
+ ...restOptions,
45
+ signal: abortController.signal,
46
+ });
47
+ }, []);
9
48
  }
10
- exports.useSafeFetch = useSafeFetch;
@@ -1 +1,3 @@
1
- export declare function useSafeState(initialValue?: null): (((value: any) => void) | null)[];
1
+ type SetStateAction<T> = T | ((prevState: T) => T);
2
+ export declare function useSafeState<T = unknown>(initialValue?: T | (() => T)): [T, (value: SetStateAction<T>) => void];
3
+ export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useSafeState = void 0;
3
+ exports.useSafeState = useSafeState;
4
4
  const react_1 = require("react");
5
5
  function useSafeState(initialValue = null) {
6
6
  const isMounted = (0, react_1.useRef)(true);
@@ -17,4 +17,3 @@ function useSafeState(initialValue = null) {
17
17
  }, []);
18
18
  return [state, setStateSafe];
19
19
  }
20
- exports.useSafeState = useSafeState;
@@ -1 +1,36 @@
1
- export declare const useScript: (url: string) => void;
1
+ export type UseScriptStatus = 'idle' | 'loading' | 'ready' | 'error';
2
+ export type UseScriptOptions = {
3
+ /**
4
+ * Callback called when script is loaded successfully
5
+ */
6
+ onLoad?: () => void;
7
+ /**
8
+ * Callback called when script fails to load
9
+ */
10
+ onError?: () => void;
11
+ /**
12
+ * Whether to remove the script tag when the component unmounts
13
+ * @default true
14
+ */
15
+ removeOnUnmount?: boolean;
16
+ };
17
+ /**
18
+ * Hook to dynamically load external scripts.
19
+ * Returns the loading status of the script.
20
+ *
21
+ * @param url - The URL of the script to load
22
+ * @param options - Optional callbacks and configuration
23
+ * @returns The current status of the script: 'idle' | 'loading' | 'ready' | 'error'
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * const status = useScript('https://example.com/script.js', {
28
+ * onLoad: () => console.log('Script loaded'),
29
+ * onError: () => console.error('Script failed to load'),
30
+ * });
31
+ *
32
+ * if (status === 'loading') return <div>Loading...</div>;
33
+ * if (status === 'error') return <div>Error loading script</div>;
34
+ * ```
35
+ */
36
+ export declare const useScript: (url: string, options?: UseScriptOptions) => UseScriptStatus;
@@ -2,15 +2,67 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useScript = void 0;
4
4
  const react_1 = require("react");
5
- const useScript = (url) => {
5
+ /**
6
+ * Hook to dynamically load external scripts.
7
+ * Returns the loading status of the script.
8
+ *
9
+ * @param url - The URL of the script to load
10
+ * @param options - Optional callbacks and configuration
11
+ * @returns The current status of the script: 'idle' | 'loading' | 'ready' | 'error'
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * const status = useScript('https://example.com/script.js', {
16
+ * onLoad: () => console.log('Script loaded'),
17
+ * onError: () => console.error('Script failed to load'),
18
+ * });
19
+ *
20
+ * if (status === 'loading') return <div>Loading...</div>;
21
+ * if (status === 'error') return <div>Error loading script</div>;
22
+ * ```
23
+ */
24
+ const useScript = (url, options = {}) => {
25
+ const { onLoad, onError, removeOnUnmount = true } = options;
26
+ const [status, setStatus] = (0, react_1.useState)('idle');
27
+ const callbacksRef = (0, react_1.useRef)({ onLoad, onError });
28
+ // Keep callbacks ref updated
6
29
  (0, react_1.useEffect)(() => {
30
+ callbacksRef.current = { onLoad, onError };
31
+ }, [onLoad, onError]);
32
+ (0, react_1.useEffect)(() => {
33
+ // Find existing script safely (avoid CSS selector injection)
34
+ const existingScript = Array.from(document.querySelectorAll('script')).find((s) => s.src === url || s.getAttribute('src') === url);
35
+ if (existingScript) {
36
+ const isLoaded = existingScript.readyState ===
37
+ 'complete' ||
38
+ existingScript.readyState ===
39
+ 'loaded';
40
+ setStatus(isLoaded ? 'ready' : 'loading');
41
+ return;
42
+ }
43
+ setStatus('loading');
7
44
  const script = document.createElement('script');
8
45
  script.src = url;
9
46
  script.async = true;
47
+ const handleLoad = () => {
48
+ setStatus('ready');
49
+ callbacksRef.current.onLoad?.();
50
+ };
51
+ const handleError = () => {
52
+ setStatus('error');
53
+ callbacksRef.current.onError?.();
54
+ };
55
+ script.addEventListener('load', handleLoad);
56
+ script.addEventListener('error', handleError);
10
57
  document.body.appendChild(script);
11
58
  return () => {
12
- document.body.removeChild(script);
59
+ script.removeEventListener('load', handleLoad);
60
+ script.removeEventListener('error', handleError);
61
+ if (removeOnUnmount && script.parentNode) {
62
+ script.parentNode.removeChild(script);
63
+ }
13
64
  };
14
- }, [url]);
65
+ }, [url, removeOnUnmount]);
66
+ return status;
15
67
  };
16
68
  exports.useScript = useScript;
@@ -1,2 +1,24 @@
1
- import { MouseEventHandler } from 'react';
2
- export declare const useTheme: () => [string, MouseEventHandler, boolean];
1
+ export type ThemeMode = 'light' | 'dark';
2
+ /**
3
+ * Hook to manage theme (light/dark) with localStorage persistence.
4
+ * Automatically detects system color scheme preference.
5
+ *
6
+ * @returns A tuple containing:
7
+ * - current theme mode ('light' | 'dark')
8
+ * - function to toggle between themes
9
+ * - boolean indicating if the component is mounted (useful for SSR)
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * const [theme, toggleTheme, mounted] = useTheme();
14
+ *
15
+ * if (!mounted) return null; // Avoid hydration mismatch
16
+ *
17
+ * return (
18
+ * <button onClick={toggleTheme}>
19
+ * Switch to {theme === 'light' ? 'dark' : 'light'} mode
20
+ * </button>
21
+ * );
22
+ * ```
23
+ */
24
+ export declare const useTheme: () => [ThemeMode, () => void, boolean];