@alessiofrittoli/react-hooks 3.0.0 → 3.2.0-alpha.1

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/README.md CHANGED
@@ -267,9 +267,13 @@ Get Document Media matches and listen for changes.
267
267
 
268
268
  <summary style="cursor:pointer">Parameters</summary>
269
269
 
270
- | Parameter | Type | Description |
271
- |-----------|----------|-------------|
272
- | `query` | `string` | A string specifying the media query to parse into a `MediaQueryList`. |
270
+ | Parameter | Type | Default | Description |
271
+ |-----------|----------|---------|-------------|
272
+ | `query` | `string` | - | A string specifying the media query to parse into a `MediaQueryList`. |
273
+ | `options` | `UseMediaQueryOptions\|UseMediaQueryStateOptions` | - | An object defining custom options. |
274
+ | `options.updateState` | `boolean` | `true` | Indicates whether the hook will dispatch a React state update when the given `query` change event get dispatched. |
275
+ | `options.onChange` | `OnChangeHandler` | - | A custom callback that will be invoked on initial page load and when the given `query` change event get dispatched. |
276
+ | | | | This callback is required if `updateState` is set to `false`. |
273
277
 
274
278
  </details>
275
279
 
@@ -279,10 +283,10 @@ Get Document Media matches and listen for changes.
279
283
 
280
284
  <summary style="cursor:pointer">Returns</summary>
281
285
 
282
- Type: `boolean`
286
+ Type: `boolean|void`
283
287
 
284
- - `true` if the document currently matches the media query list.
285
- - `false` otherwise.
288
+ - `true` or `false` if the document currently matches the media query list or not.
289
+ - `void` if `updateState` is set to `false`.
286
290
 
287
291
  </details>
288
292
 
@@ -300,6 +304,21 @@ import { useMediaQuery } from '@alessiofrittoli/react-hooks'
300
304
  const isDarkOS = useMediaQuery( '(prefers-color-scheme: dark)' )
301
305
  ```
302
306
 
307
+ ---
308
+
309
+ ###### Listen changes with no state updates
310
+
311
+ ```tsx
312
+ import { useMediaQuery } from '@alessiofrittoli/react-hooks'
313
+
314
+ useMediaQuery( '(prefers-color-scheme: dark)', {
315
+ updateState: false,
316
+ onChange( matches ) {
317
+ console.log( 'is dark OS?', matches )
318
+ }
319
+ } )
320
+ ```
321
+
303
322
  </details>
304
323
 
305
324
  ---
package/dist/index.d.mts CHANGED
@@ -481,15 +481,50 @@ declare function useEventListener<T extends Record<string, Event>, K extends key
481
481
  */
482
482
  declare const useIsPortrait: () => boolean;
483
483
 
484
+ type OnChangeHandler = (matches: boolean) => void;
485
+ interface CommonOptions {
486
+ /**
487
+ * A custom callback that will be invoked on initial page load and when the given `query` change event get dispatched.
488
+ *
489
+ * @param matches Whether the document currently matches the media query list.
490
+ */
491
+ onChange?: OnChangeHandler;
492
+ }
493
+ interface UseMediaQueryOptions extends CommonOptions {
494
+ /**
495
+ * Indicates whether the hook will dispatch a React state update when the given `query` change event get dispatched.
496
+ *
497
+ */
498
+ updateState: false;
499
+ onChange: OnChangeHandler;
500
+ }
501
+ interface UseMediaQueryStateOptions extends CommonOptions {
502
+ /**
503
+ * Indicates whether the hook will dispatch a React state update when the given `query` change event get dispatched.
504
+ *
505
+ */
506
+ updateState?: true;
507
+ }
484
508
  /**
485
- * Get Document Media matches and listen for changes.
509
+ * Get Document Media matches and dispatch a React state update on MediaQuery changes.
486
510
  *
487
511
  * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
488
512
  *
489
- * @param query A string specifying the media query to parse into a `MediaQueryList`.
513
+ * @param query A string specifying the media query to parse into a `MediaQueryList`.
514
+ * @param options An object defining custom options. See {@linkcode UseMediaQueryStateOptions} for more info.
515
+ *
490
516
  * @returns A boolean value that returns `true` if the document currently matches the media query list, or `false` if not.
491
517
  */
492
- declare const useMediaQuery: (query: string) => boolean;
518
+ declare function useMediaQuery(query: string, options?: UseMediaQueryStateOptions): boolean;
519
+ /**
520
+ * Get Document Media matches and listen for changes.
521
+ *
522
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
523
+ *
524
+ * @param query A string specifying the media query to parse into a `MediaQueryList`.
525
+ * @param options An object defining custom options. See {@linkcode UseMediaQueryOptions} for more info.
526
+ */
527
+ declare function useMediaQuery(query: string, options?: UseMediaQueryOptions): void;
493
528
 
494
529
  type SetFocusTrap = (target?: HTMLElement) => void;
495
530
  type RestoreFocusTrap = () => void;
@@ -701,6 +736,13 @@ declare const useInView: (target: React.RefObject<Element | null>, options?: Use
701
736
  */
702
737
  declare const useScrollBlock: (target?: React.RefObject<HTMLElement | null>) => readonly [() => void, () => void];
703
738
 
739
+ /**
740
+ * Modified version of `useEffect` that only run once on intial load.
741
+ *
742
+ * @param effect Imperative function that can return a cleanup function.
743
+ */
744
+ declare const useEffectOnce: (effect: React.EffectCallback) => void;
745
+
704
746
  /**
705
747
  * Check if the React Hook or Component where this hook is executed is running in a browser environment.
706
748
  *
@@ -1012,4 +1054,4 @@ declare function useTimeout<T extends readonly unknown[]>(callback: TimerHandler
1012
1054
  */
1013
1055
  declare const useLightTimeout: <T extends readonly unknown[]>(callback: TimerHandler<T>, options?: BasicTimerOptions<T>) => void;
1014
1056
 
1015
- export { type AddEventListenerOptions, type BasicTimerOptions, type CommonListenerOptions, type CustomEventListenerOptions, type DocumentEventListener, type DocumentListenerOptions, type ElementEventListener, type ElementListenerOptions, type IntersectionState, type ListenerOptions, type MarginType, type MarginValue, type MediaQueryChangeListener, type MediaQueryEventListener, type MediaQueryListenerOptions, type OnIntersectHandler, type OnIntersectStateHandler, type StartTimer, type StateTimerOptions, type StateTimerReturnType, type StopTimer, type TimerHandler, type TimerId, type TimerOptions, type TimerReturnType, type UseDarkModeOptions, type UseDarkModeOutput, type UseInViewOptions, type UseInViewReturnType, type UseIntervalWhenVisibleReturnType, type UseIntervalWhenVisibleStateReturnType, type WindowEventListener, type WindowListenerOptions, useDarkMode, useDebounce, useEventListener, useFocusTrap, useInView, useInterval, useIntervalWhenVisible, useIsClient, useIsFirstRender, useIsPortrait, useLightInterval, useLightTimeout, useLocalStorage, useMediaQuery, useScrollBlock, useSessionStorage, useStorage, useTimeout, useUpdateEffect };
1057
+ export { type AddEventListenerOptions, type BasicTimerOptions, type CommonListenerOptions, type CustomEventListenerOptions, type DocumentEventListener, type DocumentListenerOptions, type ElementEventListener, type ElementListenerOptions, type IntersectionState, type ListenerOptions, type MarginType, type MarginValue, type MediaQueryChangeListener, type MediaQueryEventListener, type MediaQueryListenerOptions, type OnChangeHandler, type OnIntersectHandler, type OnIntersectStateHandler, type StartTimer, type StateTimerOptions, type StateTimerReturnType, type StopTimer, type TimerHandler, type TimerId, type TimerOptions, type TimerReturnType, type UseDarkModeOptions, type UseDarkModeOutput, type UseInViewOptions, type UseInViewReturnType, type UseIntervalWhenVisibleReturnType, type UseIntervalWhenVisibleStateReturnType, type UseMediaQueryOptions, type UseMediaQueryStateOptions, type WindowEventListener, type WindowListenerOptions, useDarkMode, useDebounce, useEffectOnce, useEventListener, useFocusTrap, useInView, useInterval, useIntervalWhenVisible, useIsClient, useIsFirstRender, useIsPortrait, useLightInterval, useLightTimeout, useLocalStorage, useMediaQuery, useScrollBlock, useSessionStorage, useStorage, useTimeout, useUpdateEffect };
package/dist/index.d.ts CHANGED
@@ -481,15 +481,50 @@ declare function useEventListener<T extends Record<string, Event>, K extends key
481
481
  */
482
482
  declare const useIsPortrait: () => boolean;
483
483
 
484
+ type OnChangeHandler = (matches: boolean) => void;
485
+ interface CommonOptions {
486
+ /**
487
+ * A custom callback that will be invoked on initial page load and when the given `query` change event get dispatched.
488
+ *
489
+ * @param matches Whether the document currently matches the media query list.
490
+ */
491
+ onChange?: OnChangeHandler;
492
+ }
493
+ interface UseMediaQueryOptions extends CommonOptions {
494
+ /**
495
+ * Indicates whether the hook will dispatch a React state update when the given `query` change event get dispatched.
496
+ *
497
+ */
498
+ updateState: false;
499
+ onChange: OnChangeHandler;
500
+ }
501
+ interface UseMediaQueryStateOptions extends CommonOptions {
502
+ /**
503
+ * Indicates whether the hook will dispatch a React state update when the given `query` change event get dispatched.
504
+ *
505
+ */
506
+ updateState?: true;
507
+ }
484
508
  /**
485
- * Get Document Media matches and listen for changes.
509
+ * Get Document Media matches and dispatch a React state update on MediaQuery changes.
486
510
  *
487
511
  * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
488
512
  *
489
- * @param query A string specifying the media query to parse into a `MediaQueryList`.
513
+ * @param query A string specifying the media query to parse into a `MediaQueryList`.
514
+ * @param options An object defining custom options. See {@linkcode UseMediaQueryStateOptions} for more info.
515
+ *
490
516
  * @returns A boolean value that returns `true` if the document currently matches the media query list, or `false` if not.
491
517
  */
492
- declare const useMediaQuery: (query: string) => boolean;
518
+ declare function useMediaQuery(query: string, options?: UseMediaQueryStateOptions): boolean;
519
+ /**
520
+ * Get Document Media matches and listen for changes.
521
+ *
522
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
523
+ *
524
+ * @param query A string specifying the media query to parse into a `MediaQueryList`.
525
+ * @param options An object defining custom options. See {@linkcode UseMediaQueryOptions} for more info.
526
+ */
527
+ declare function useMediaQuery(query: string, options?: UseMediaQueryOptions): void;
493
528
 
494
529
  type SetFocusTrap = (target?: HTMLElement) => void;
495
530
  type RestoreFocusTrap = () => void;
@@ -701,6 +736,13 @@ declare const useInView: (target: React.RefObject<Element | null>, options?: Use
701
736
  */
702
737
  declare const useScrollBlock: (target?: React.RefObject<HTMLElement | null>) => readonly [() => void, () => void];
703
738
 
739
+ /**
740
+ * Modified version of `useEffect` that only run once on intial load.
741
+ *
742
+ * @param effect Imperative function that can return a cleanup function.
743
+ */
744
+ declare const useEffectOnce: (effect: React.EffectCallback) => void;
745
+
704
746
  /**
705
747
  * Check if the React Hook or Component where this hook is executed is running in a browser environment.
706
748
  *
@@ -1012,4 +1054,4 @@ declare function useTimeout<T extends readonly unknown[]>(callback: TimerHandler
1012
1054
  */
1013
1055
  declare const useLightTimeout: <T extends readonly unknown[]>(callback: TimerHandler<T>, options?: BasicTimerOptions<T>) => void;
1014
1056
 
1015
- export { type AddEventListenerOptions, type BasicTimerOptions, type CommonListenerOptions, type CustomEventListenerOptions, type DocumentEventListener, type DocumentListenerOptions, type ElementEventListener, type ElementListenerOptions, type IntersectionState, type ListenerOptions, type MarginType, type MarginValue, type MediaQueryChangeListener, type MediaQueryEventListener, type MediaQueryListenerOptions, type OnIntersectHandler, type OnIntersectStateHandler, type StartTimer, type StateTimerOptions, type StateTimerReturnType, type StopTimer, type TimerHandler, type TimerId, type TimerOptions, type TimerReturnType, type UseDarkModeOptions, type UseDarkModeOutput, type UseInViewOptions, type UseInViewReturnType, type UseIntervalWhenVisibleReturnType, type UseIntervalWhenVisibleStateReturnType, type WindowEventListener, type WindowListenerOptions, useDarkMode, useDebounce, useEventListener, useFocusTrap, useInView, useInterval, useIntervalWhenVisible, useIsClient, useIsFirstRender, useIsPortrait, useLightInterval, useLightTimeout, useLocalStorage, useMediaQuery, useScrollBlock, useSessionStorage, useStorage, useTimeout, useUpdateEffect };
1057
+ export { type AddEventListenerOptions, type BasicTimerOptions, type CommonListenerOptions, type CustomEventListenerOptions, type DocumentEventListener, type DocumentListenerOptions, type ElementEventListener, type ElementListenerOptions, type IntersectionState, type ListenerOptions, type MarginType, type MarginValue, type MediaQueryChangeListener, type MediaQueryEventListener, type MediaQueryListenerOptions, type OnChangeHandler, type OnIntersectHandler, type OnIntersectStateHandler, type StartTimer, type StateTimerOptions, type StateTimerReturnType, type StopTimer, type TimerHandler, type TimerId, type TimerOptions, type TimerReturnType, type UseDarkModeOptions, type UseDarkModeOutput, type UseInViewOptions, type UseInViewReturnType, type UseIntervalWhenVisibleReturnType, type UseIntervalWhenVisibleStateReturnType, type UseMediaQueryOptions, type UseMediaQueryStateOptions, type WindowEventListener, type WindowListenerOptions, useDarkMode, useDebounce, useEffectOnce, useEventListener, useFocusTrap, useInView, useInterval, useIntervalWhenVisible, useIsClient, useIsFirstRender, useIsPortrait, useLightInterval, useLightTimeout, useLocalStorage, useMediaQuery, useScrollBlock, useSessionStorage, useStorage, useTimeout, useUpdateEffect };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _react = require('react');var _LocalStorage = require('@alessiofrittoli/web-utils/storage/LocalStorage');var _SessionStorage = require('@alessiofrittoli/web-utils/storage/SessionStorage');var g=(e,r,t="local")=>{let n=_react.useCallback.call(void 0, ()=>_nullishCoalesce((t==="local"?_LocalStorage.LocalStorage:_SessionStorage.SessionStorage).get(e), () => (r)),[t,e,r]),[i,a]=_react.useState.call(void 0, r),o=_react.useCallback.call(void 0, s=>{a(l=>{let c=s instanceof Function?s(l):s;return(typeof window<"u"&&t==="local"?_LocalStorage.LocalStorage:_SessionStorage.SessionStorage).set(e,c),c})},[t,e]);return _react.useEffect.call(void 0, ()=>{a(n())},[n]),[i,o]};var V=(e,r)=>g(e,r,"local");var we=(e,r)=>g(e,r,"session");var K=()=>{let[e,r]=_react.useState.call(void 0, !1);return _react.useEffect.call(void 0, ()=>r(!0),[]),e};var W=()=>{let e=_react.useRef.call(void 0, !0);return e.current?(e.current=!1,!0):e.current};var L=(e,r)=>{let t=W();_react.useEffect.call(void 0, ()=>{if(!t)return e()},r)};var _browserapi = require('@alessiofrittoli/web-utils/browser-api');var S=e=>{let[r,t]=_react.useState.call(void 0, _browserapi.getMediaMatches.call(void 0, e)),n=_react.useCallback.call(void 0, ()=>t(_browserapi.getMediaMatches.call(void 0, e)),[e]);return _react.useEffect.call(void 0, ()=>{let i=window.matchMedia(e);return n(),i.addEventListener("change",n),()=>{i.removeEventListener("change",n)}},[e,n]),r};var _e=(e={})=>{let r=K(),t=S("(prefers-color-scheme: dark)"),{initial:n=t,docClassNames:i=[]}=e,[a,o]=V("dark-mode",n),s=_nullishCoalesce(a, () => (t)),[l,c]=i,u=_react.useRef.call(void 0, {light:"",dark:""});return L(()=>{o(t)},[t,o]),_react.useEffect.call(void 0, ()=>{l&&document.documentElement.classList.toggle(l,s),c&&document.documentElement.classList.toggle(c,!s)},[s,l,c]),_react.useEffect.call(void 0, ()=>{document.head.querySelectorAll('meta[name="theme-color"]').forEach(p=>{let d=p.getAttribute("media"),f=p.getAttribute("content");if(f){if(!d||d==="(prefers-color-scheme: light)"){u.current.light=f;return}u.current.dark=f}})},[]),L(()=>{let p=u.current.dark,d=u.current.light;a&&!p||!a&&!d||document.head.querySelectorAll('meta[name="theme-color"]').forEach(f=>{f.setAttribute("content",a?p:d)})},[a]),{isDarkMode:r?s:!1,isDarkOS:r?t:!1,toggleDarkMode:_react.useCallback.call(void 0, ()=>o(p=>!p),[o]),enableDarkMode:_react.useCallback.call(void 0, ()=>o(!0),[o]),disableDarkMode:_react.useCallback.call(void 0, ()=>o(!1),[o])}};function rt(e,r){let{target:t,query:n,options:i,listener:a,onLoad:o,onCleanUp:s}=r;_react.useEffect.call(void 0, ()=>{let l=Array.isArray(e)?e:[e],c=_nullishCoalesce((n?window.matchMedia(n):t&&"current"in t?t.current:t), () => (window));if(c.addEventListener)return _optionalChain([o, 'optionalCall', _2 => _2()]),l.map(u=>{c.addEventListener(u,a,i)}),()=>{l.map(u=>{c.removeEventListener(u,a,i)}),_optionalChain([s, 'optionalCall', _3 => _3()])}},[e,t,n,i,a,o,s])}var _device = require('@alessiofrittoli/web-utils/device');var ut=()=>S(_device.portraitMediaQuery);var ae=["input","select","textarea","button","[href]",'[tabindex]:not([tabindex="-1"])'].join(", "),mt= exports.useFocusTrap =e=>{let[r,t]=_react.useState.call(void 0, !1),n=_react.useRef.call(void 0, null),i=_react.useCallback.call(void 0, o=>{n.current=document.activeElement;let s=o||_optionalChain([e, 'optionalAccess', _4 => _4.current])||!1;if(s)return t(s)},[e]),a=_react.useCallback.call(void 0, ()=>{_optionalChain([n, 'access', _5 => _5.current, 'optionalAccess', _6 => _6.focus, 'call', _7 => _7()]),t(!1)},[]);return _react.useEffect.call(void 0, ()=>{if(!r)return;let o=s=>{if(s.key!=="Tab")return;let l=Array.from(r.querySelectorAll(ae)),c=l.at(0),u=l.at(-1);if(!s.shiftKey){document.activeElement===u&&(s.preventDefault(),_optionalChain([c, 'optionalAccess', _8 => _8.focus, 'call', _9 => _9()]));return}document.activeElement===c&&(s.preventDefault(),_optionalChain([u, 'optionalAccess', _10 => _10.focus, 'call', _11 => _11()]))};return document.addEventListener("keydown",o),()=>{document.removeEventListener("keydown",o)}},[r]),[i,a]};var Et=(e,r={})=>{let{initial:t=!1,once:n,amount:i,margin:a,root:o,enable:s=!0}=r,{onEnter:l,onExit:c,onIntersect:u}=r,p=_react.useRef.call(void 0, !0),[d,f]=_react.useState.call(void 0, t),[y,N]=_react.useState.call(void 0, s),O=_react.useRef.call(void 0, null),x=_react.useRef.call(void 0, !1),v=_react.useMemo.call(void 0, ()=>{if(!y||typeof IntersectionObserver>"u")return;let P=i==="all"?1:i==="some"?.5:i;try{return new IntersectionObserver(async([E],M)=>{if(!E)return;let T=E.isIntersecting;try{if(x.current=!T&&!!O.current,T&&l&&await l({entry:E,observer:M}),x.current&&c&&await c({entry:E,observer:M}),u&&(T||!T&&O.current!=null)){let b={isEntering:T,isExiting:x.current};await u({entry:E,observer:M,...b})}if(O.current=T,!p.current)return;f(T)}catch(b){console.error(b)}T&&n&&M.disconnect()},{root:o||void 0,rootMargin:a,threshold:P})}catch(E){console.error(E)}},[o,a,i,n,y,l,c,u]);return _react.useEffect.call(void 0, ()=>{if(p.current=!0,!(!y||!e.current||!v))return v.observe(e.current),()=>{p.current=!1,v.disconnect()}},[e,v,y]),{inView:d,enabled:y,observer:v,isExiting:x.current,setInView:f,setEnabled:N}};var _dom = require('@alessiofrittoli/web-utils/dom');var gt=e=>{let r=_react.useCallback.call(void 0, ()=>_dom.blockScroll.call(void 0, _optionalChain([e, 'optionalAccess', _12 => _12.current])||void 0),[e]),t=_react.useCallback.call(void 0, ()=>_dom.restoreScroll.call(void 0, _optionalChain([e, 'optionalAccess', _13 => _13.current])||void 0),[e]);return[r,t]};var j=(e,r={})=>{let{delay:t=1,args:n}=r;_react.useEffect.call(void 0, ()=>{let i=setTimeout(e,t,...n||[]);return()=>clearTimeout(i)},[t,n,e])};var ht=(e,r=500)=>{let[t,n]=_react.useState.call(void 0, e),i=_react.useMemo.call(void 0, ()=>[e],[e]);return j(n,{delay:r,args:i}),t};function B(e,r={}){let{delay:t=1,args:n,autoplay:i=!0,runOnStart:a=!1,updateState:o=!1}=r,s=_react.useRef.call(void 0, void 0),[l,c]=_react.useState.call(void 0, i),u=_react.useCallback.call(void 0, ()=>s.current?(clearInterval(s.current),s.current=void 0,!0):!1,[]),p=_react.useCallback.call(void 0, ()=>{let f=u();return a&&(n?e(...n):e()),s.current=setInterval(e,t,...n||[]),!f&&o&&c(!0),s.current},[t,n,o,a,e,u]),d=_react.useCallback.call(void 0, ()=>{u()&&o&&c(!1)},[o,u]);return _react.useEffect.call(void 0, ()=>{if(i)return p(),d},[i,p,d]),o?{isActive:l,start:p,stop:d}:{start:p,stop:d}}var Wt=(e,r={})=>{let{delay:t=1,args:n}=r;_react.useEffect.call(void 0, ()=>{let i=setInterval(e,t,...n||[]);return()=>clearInterval(i)},[t,n,e])};function $t(e,r={}){let{autoplay:t=!0}=r,n=B(e,{autoplay:!1,...r}),{start:i,stop:a}=n,o=_react.useCallback.call(void 0, ()=>document.hidden?a():i(),[i,a]),s=_react.useCallback.call(void 0, ()=>{if(document.addEventListener("visibilitychange",o),!document.hidden)return i()},[i,o]),l=_react.useCallback.call(void 0, ()=>{a(),document.removeEventListener("visibilitychange",o)},[a,o]);return _react.useEffect.call(void 0, ()=>{if(t)return s(),l},[t,s,l]),{...n,start:s,stop:l}}function Pt(e,r={}){let{delay:t=1,args:n,autoplay:i=!0,runOnStart:a=!1,updateState:o=!1}=r,s=_react.useRef.call(void 0, void 0),[l,c]=_react.useState.call(void 0, i),u=_react.useCallback.call(void 0, ()=>s.current?(clearTimeout(s.current),s.current=void 0,!0):!1,[]),p=_react.useCallback.call(void 0, ()=>{let f=u();return a&&(n?e(...n):e()),s.current=setTimeout(()=>{if(s.current=void 0,o&&c(!1),n)return e(...n);e()},t),!f&&o&&c(!0),s.current},[t,n,o,a,e,u]),d=_react.useCallback.call(void 0, ()=>{u()&&o&&c(!1)},[o,u]);return _react.useEffect.call(void 0, ()=>{if(i)return p(),d},[i,p,d]),o?{isActive:l,start:p,stop:d}:{start:p,stop:d}}exports.useDarkMode = _e; exports.useDebounce = ht; exports.useEventListener = rt; exports.useFocusTrap = mt; exports.useInView = Et; exports.useInterval = B; exports.useIntervalWhenVisible = $t; exports.useIsClient = K; exports.useIsFirstRender = W; exports.useIsPortrait = ut; exports.useLightInterval = Wt; exports.useLightTimeout = j; exports.useLocalStorage = V; exports.useMediaQuery = S; exports.useScrollBlock = gt; exports.useSessionStorage = we; exports.useStorage = g; exports.useTimeout = Pt; exports.useUpdateEffect = L;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _react = require('react');var _LocalStorage = require('@alessiofrittoli/web-utils/storage/LocalStorage');var _SessionStorage = require('@alessiofrittoli/web-utils/storage/SessionStorage');var g=(e,o,t="local")=>{let s=_react.useCallback.call(void 0, ()=>_nullishCoalesce((t==="local"?_LocalStorage.LocalStorage:_SessionStorage.SessionStorage).get(e), () => (o)),[t,e,o]),[i,a]=_react.useState.call(void 0, o),r=_react.useCallback.call(void 0, n=>{a(u=>{let l=n instanceof Function?n(u):n;return(typeof window<"u"&&t==="local"?_LocalStorage.LocalStorage:_SessionStorage.SessionStorage).set(e,l),l})},[t,e]);return _react.useEffect.call(void 0, ()=>{a(s())},[s]),[i,r]};var K=(e,o)=>g(e,o,"local");var we=(e,o)=>g(e,o,"session");var O=()=>{let e=_react.useRef.call(void 0, !0);return e.current?(e.current=!1,!0):e.current};var $e=e=>{let o=O();_react.useEffect.call(void 0, ()=>{if(o)return e()},[])};var W=()=>{let[e,o]=_react.useState.call(void 0, !1);return _react.useEffect.call(void 0, ()=>o(!0),[]),e};var k=(e,o)=>{let t=O();_react.useEffect.call(void 0, ()=>{if(!t)return e()},o)};var _browserapi = require('@alessiofrittoli/web-utils/browser-api');function S(e,o={}){let{updateState:t=!0,onChange:s}=o,[i,a]=_react.useState.call(void 0, _browserapi.getMediaMatches.call(void 0, e)),r=_react.useCallback.call(void 0, ()=>{let n=_browserapi.getMediaMatches.call(void 0, e);t&&a(n),_optionalChain([s, 'optionalCall', _2 => _2(n)])},[e,t,s]);if(_react.useEffect.call(void 0, ()=>{let n=window.matchMedia(e),{matches:u}=n;return t&&a(u),_optionalChain([s, 'optionalCall', _3 => _3(u)]),n.addEventListener("change",r),()=>{n.removeEventListener("change",r)}},[e,t,s,r]),!!t)return i}var st=(e={})=>{let o=W(),t=S("(prefers-color-scheme: dark)"),{initial:s=t,docClassNames:i=[]}=e,[a,r]=K("dark-mode",s),n=_nullishCoalesce(a, () => (t)),[u,l]=i,c=_react.useRef.call(void 0, {light:"",dark:""});return k(()=>{r(t)},[t,r]),_react.useEffect.call(void 0, ()=>{u&&document.documentElement.classList.toggle(u,n),l&&document.documentElement.classList.toggle(l,!n)},[n,u,l]),_react.useEffect.call(void 0, ()=>{document.head.querySelectorAll('meta[name="theme-color"]').forEach(p=>{let d=p.getAttribute("media"),f=p.getAttribute("content");if(f){if(!d||d==="(prefers-color-scheme: light)"){c.current.light=f;return}c.current.dark=f}})},[]),k(()=>{let p=c.current.dark,d=c.current.light;a&&!p||!a&&!d||document.head.querySelectorAll('meta[name="theme-color"]').forEach(f=>{f.setAttribute("content",a?p:d)})},[a]),{isDarkMode:o?n:!1,isDarkOS:o?t:!1,toggleDarkMode:_react.useCallback.call(void 0, ()=>r(p=>!p),[r]),enableDarkMode:_react.useCallback.call(void 0, ()=>r(!0),[r]),disableDarkMode:_react.useCallback.call(void 0, ()=>r(!1),[r])}};function ct(e,o){let{target:t,query:s,options:i,listener:a,onLoad:r,onCleanUp:n}=o;_react.useEffect.call(void 0, ()=>{let u=Array.isArray(e)?e:[e],l=_nullishCoalesce((s?window.matchMedia(s):t&&"current"in t?t.current:t), () => (window));if(l.addEventListener)return _optionalChain([r, 'optionalCall', _4 => _4()]),u.map(c=>{l.addEventListener(c,a,i)}),()=>{u.map(c=>{l.removeEventListener(c,a,i)}),_optionalChain([n, 'optionalCall', _5 => _5()])}},[e,t,s,i,a,r,n])}var _device = require('@alessiofrittoli/web-utils/device');var ft=()=>S(_device.portraitMediaQuery);var ue=["input","select","textarea","button","[href]",'[tabindex]:not([tabindex="-1"])'].join(", "),vt= exports.useFocusTrap =e=>{let[o,t]=_react.useState.call(void 0, !1),s=_react.useRef.call(void 0, null),i=_react.useCallback.call(void 0, r=>{s.current=document.activeElement;let n=r||_optionalChain([e, 'optionalAccess', _6 => _6.current])||!1;if(n)return t(n)},[e]),a=_react.useCallback.call(void 0, ()=>{_optionalChain([s, 'access', _7 => _7.current, 'optionalAccess', _8 => _8.focus, 'call', _9 => _9()]),t(!1)},[]);return _react.useEffect.call(void 0, ()=>{if(!o)return;let r=n=>{if(n.key!=="Tab")return;let u=Array.from(o.querySelectorAll(ue)),l=u.at(0),c=u.at(-1);if(!n.shiftKey){document.activeElement===c&&(n.preventDefault(),_optionalChain([l, 'optionalAccess', _10 => _10.focus, 'call', _11 => _11()]));return}document.activeElement===l&&(n.preventDefault(),_optionalChain([c, 'optionalAccess', _12 => _12.focus, 'call', _13 => _13()]))};return document.addEventListener("keydown",r),()=>{document.removeEventListener("keydown",r)}},[o]),[i,a]};var Ot=(e,o={})=>{let{initial:t=!1,once:s,amount:i,margin:a,root:r,enable:n=!0}=o,{onEnter:u,onExit:l,onIntersect:c}=o,p=_react.useRef.call(void 0, !0),[d,f]=_react.useState.call(void 0, t),[E,q]=_react.useState.call(void 0, n),b=_react.useRef.call(void 0, null),x=_react.useRef.call(void 0, !1),v=_react.useMemo.call(void 0, ()=>{if(!E||typeof IntersectionObserver>"u")return;let N=i==="all"?1:i==="some"?.5:i;try{return new IntersectionObserver(async([y],M)=>{if(!y)return;let T=y.isIntersecting;try{if(x.current=!T&&!!b.current,T&&u&&await u({entry:y,observer:M}),x.current&&l&&await l({entry:y,observer:M}),c&&(T||!T&&b.current!=null)){let L={isEntering:T,isExiting:x.current};await c({entry:y,observer:M,...L})}if(b.current=T,!p.current)return;f(T)}catch(L){console.error(L)}T&&s&&M.disconnect()},{root:r||void 0,rootMargin:a,threshold:N})}catch(y){console.error(y)}},[r,a,i,s,E,u,l,c]);return _react.useEffect.call(void 0, ()=>{if(p.current=!0,!(!E||!e.current||!v))return v.observe(e.current),()=>{p.current=!1,v.disconnect()}},[e,v,E]),{inView:d,enabled:E,observer:v,isExiting:x.current,setInView:f,setEnabled:q}};var _dom = require('@alessiofrittoli/web-utils/dom');var ht=e=>{let o=_react.useCallback.call(void 0, ()=>_dom.blockScroll.call(void 0, _optionalChain([e, 'optionalAccess', _14 => _14.current])||void 0),[e]),t=_react.useCallback.call(void 0, ()=>_dom.restoreScroll.call(void 0, _optionalChain([e, 'optionalAccess', _15 => _15.current])||void 0),[e]);return[o,t]};var j=(e,o={})=>{let{delay:t=1,args:s}=o;_react.useEffect.call(void 0, ()=>{let i=setTimeout(e,t,...s||[]);return()=>clearTimeout(i)},[t,s,e])};var Kt=(e,o=500)=>{let[t,s]=_react.useState.call(void 0, e),i=_react.useMemo.call(void 0, ()=>[e],[e]);return j(s,{delay:o,args:i}),t};function B(e,o={}){let{delay:t=1,args:s,autoplay:i=!0,runOnStart:a=!1,updateState:r=!1}=o,n=_react.useRef.call(void 0, void 0),[u,l]=_react.useState.call(void 0, i),c=_react.useCallback.call(void 0, ()=>n.current?(clearInterval(n.current),n.current=void 0,!0):!1,[]),p=_react.useCallback.call(void 0, ()=>{let f=c();return a&&(s?e(...s):e()),n.current=setInterval(e,t,...s||[]),!f&&r&&l(!0),n.current},[t,s,r,a,e,c]),d=_react.useCallback.call(void 0, ()=>{c()&&r&&l(!1)},[r,c]);return _react.useEffect.call(void 0, ()=>{if(i)return p(),d},[i,p,d]),r?{isActive:u,start:p,stop:d}:{start:p,stop:d}}var jt=(e,o={})=>{let{delay:t=1,args:s}=o;_react.useEffect.call(void 0, ()=>{let i=setInterval(e,t,...s||[]);return()=>clearInterval(i)},[t,s,e])};function zt(e,o={}){let{autoplay:t=!0}=o,s=B(e,{autoplay:!1,...o}),{start:i,stop:a}=s,r=_react.useCallback.call(void 0, ()=>document.hidden?a():i(),[i,a]),n=_react.useCallback.call(void 0, ()=>{if(document.addEventListener("visibilitychange",r),!document.hidden)return i()},[i,r]),u=_react.useCallback.call(void 0, ()=>{a(),document.removeEventListener("visibilitychange",r)},[a,r]);return _react.useEffect.call(void 0, ()=>{if(t)return n(),u},[t,n,u]),{...s,start:n,stop:u}}function Yt(e,o={}){let{delay:t=1,args:s,autoplay:i=!0,runOnStart:a=!1,updateState:r=!1}=o,n=_react.useRef.call(void 0, void 0),[u,l]=_react.useState.call(void 0, i),c=_react.useCallback.call(void 0, ()=>n.current?(clearTimeout(n.current),n.current=void 0,!0):!1,[]),p=_react.useCallback.call(void 0, ()=>{let f=c();return a&&(s?e(...s):e()),n.current=setTimeout(()=>{if(n.current=void 0,r&&l(!1),s)return e(...s);e()},t),!f&&r&&l(!0),n.current},[t,s,r,a,e,c]),d=_react.useCallback.call(void 0, ()=>{c()&&r&&l(!1)},[r,c]);return _react.useEffect.call(void 0, ()=>{if(i)return p(),d},[i,p,d]),r?{isActive:u,start:p,stop:d}:{start:p,stop:d}}exports.useDarkMode = st; exports.useDebounce = Kt; exports.useEffectOnce = $e; exports.useEventListener = ct; exports.useFocusTrap = vt; exports.useInView = Ot; exports.useInterval = B; exports.useIntervalWhenVisible = zt; exports.useIsClient = W; exports.useIsFirstRender = O; exports.useIsPortrait = ft; exports.useLightInterval = jt; exports.useLightTimeout = j; exports.useLocalStorage = K; exports.useMediaQuery = S; exports.useScrollBlock = ht; exports.useSessionStorage = we; exports.useStorage = g; exports.useTimeout = Yt; exports.useUpdateEffect = k;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{useCallback as w,useEffect as z,useState as G}from"react";import{LocalStorage as C}from"@alessiofrittoli/web-utils/storage/LocalStorage";import{SessionStorage as V}from"@alessiofrittoli/web-utils/storage/SessionStorage";var S=(e,r,t="local")=>{let n=w(()=>(t==="local"?C:V).get(e)??r,[t,e,r]),[i,a]=G(r),o=w(s=>{a(l=>{let c=s instanceof Function?s(l):s;return(typeof window<"u"&&t==="local"?C:V).set(e,c),c})},[t,e]);return z(()=>{a(n())},[n]),[i,o]};var K=(e,r)=>S(e,r,"local");var Ce=(e,r)=>S(e,r,"session");import{useCallback as R,useEffect as F,useRef as ne}from"react";import{useEffect as J,useState as X}from"react";var W=()=>{let[e,r]=X(!1);return J(()=>r(!0),[]),e};import{useRef as Y}from"react";var A=()=>{let e=Y(!0);return e.current?(e.current=!1,!0):e.current};import{useEffect as Z}from"react";var k=(e,r)=>{let t=A();Z(()=>{if(!t)return e()},r)};import{useCallback as _,useEffect as ee,useState as te}from"react";import{getMediaMatches as U}from"@alessiofrittoli/web-utils/browser-api";var O=e=>{let[r,t]=te(U(e)),n=_(()=>t(U(e)),[e]);return ee(()=>{let i=window.matchMedia(e);return n(),i.addEventListener("change",n),()=>{i.removeEventListener("change",n)}},[e,n]),r};var et=(e={})=>{let r=W(),t=O("(prefers-color-scheme: dark)"),{initial:n=t,docClassNames:i=[]}=e,[a,o]=K("dark-mode",n),s=a??t,[l,c]=i,u=ne({light:"",dark:""});return k(()=>{o(t)},[t,o]),F(()=>{l&&document.documentElement.classList.toggle(l,s),c&&document.documentElement.classList.toggle(c,!s)},[s,l,c]),F(()=>{document.head.querySelectorAll('meta[name="theme-color"]').forEach(p=>{let f=p.getAttribute("media"),T=p.getAttribute("content");if(T){if(!f||f==="(prefers-color-scheme: light)"){u.current.light=T;return}u.current.dark=T}})},[]),k(()=>{let p=u.current.dark,f=u.current.light;a&&!p||!a&&!f||document.head.querySelectorAll('meta[name="theme-color"]').forEach(T=>{T.setAttribute("content",a?p:f)})},[a]),{isDarkMode:r?s:!1,isDarkOS:r?t:!1,toggleDarkMode:R(()=>o(p=>!p),[o]),enableDarkMode:R(()=>o(!0),[o]),disableDarkMode:R(()=>o(!1),[o])}};import{useEffect as re}from"react";function ot(e,r){let{target:t,query:n,options:i,listener:a,onLoad:o,onCleanUp:s}=r;re(()=>{let l=Array.isArray(e)?e:[e],c=(n?window.matchMedia(n):t&&"current"in t?t.current:t)??window;if(c.addEventListener)return o?.(),l.map(u=>{c.addEventListener(u,a,i)}),()=>{l.map(u=>{c.removeEventListener(u,a,i)}),s?.()}},[e,t,n,i,a,o,s])}import{portraitMediaQuery as oe}from"@alessiofrittoli/web-utils/device";var ct=()=>O(oe);import{useCallback as Q,useEffect as se,useRef as ie,useState as ae}from"react";var ue=["input","select","textarea","button","[href]",'[tabindex]:not([tabindex="-1"])'].join(", "),dt=e=>{let[r,t]=ae(!1),n=ie(null),i=Q(o=>{n.current=document.activeElement;let s=o||e?.current||!1;if(s)return t(s)},[e]),a=Q(()=>{n.current?.focus(),t(!1)},[]);return se(()=>{if(!r)return;let o=s=>{if(s.key!=="Tab")return;let l=Array.from(r.querySelectorAll(ue)),c=l.at(0),u=l.at(-1);if(!s.shiftKey){document.activeElement===u&&(s.preventDefault(),c?.focus());return}document.activeElement===c&&(s.preventDefault(),u?.focus())};return document.addEventListener("keydown",o),()=>{document.removeEventListener("keydown",o)}},[r]),[i,a]};import{useEffect as ce,useMemo as le,useRef as I,useState as $}from"react";var yt=(e,r={})=>{let{initial:t=!1,once:n,amount:i,margin:a,root:o,enable:s=!0}=r,{onEnter:l,onExit:c,onIntersect:u}=r,p=I(!0),[f,T]=$(t),[v,P]=$(s),b=I(null),M=I(!1),x=le(()=>{if(!v||typeof IntersectionObserver>"u")return;let q=i==="all"?1:i==="some"?.5:i;try{return new IntersectionObserver(async([y],g)=>{if(!y)return;let E=y.isIntersecting;try{if(M.current=!E&&!!b.current,E&&l&&await l({entry:y,observer:g}),M.current&&c&&await c({entry:y,observer:g}),u&&(E||!E&&b.current!=null)){let L={isEntering:E,isExiting:M.current};await u({entry:y,observer:g,...L})}if(b.current=E,!p.current)return;T(E)}catch(L){console.error(L)}E&&n&&g.disconnect()},{root:o||void 0,rootMargin:a,threshold:q})}catch(y){console.error(y)}},[o,a,i,n,v,l,c,u]);return ce(()=>{if(p.current=!0,!(!v||!e.current||!x))return x.observe(e.current),()=>{p.current=!1,x.disconnect()}},[e,x,v]),{inView:f,enabled:v,observer:x,isExiting:M.current,setInView:T,setEnabled:P}};import{useCallback as j}from"react";import{blockScroll as pe,restoreScroll as me}from"@alessiofrittoli/web-utils/dom";var St=e=>{let r=j(()=>pe(e?.current||void 0),[e]),t=j(()=>me(e?.current||void 0),[e]);return[r,t]};import{useMemo as fe,useState as Te}from"react";import{useEffect as de}from"react";var B=(e,r={})=>{let{delay:t=1,args:n}=r;de(()=>{let i=setTimeout(e,t,...n||[]);return()=>clearTimeout(i)},[t,n,e])};var Ht=(e,r=500)=>{let[t,n]=Te(e),i=fe(()=>[e],[e]);return B(n,{delay:r,args:i}),t};import{useCallback as h,useEffect as Ee,useRef as ye,useState as ve}from"react";function N(e,r={}){let{delay:t=1,args:n,autoplay:i=!0,runOnStart:a=!1,updateState:o=!1}=r,s=ye(void 0),[l,c]=ve(i),u=h(()=>s.current?(clearInterval(s.current),s.current=void 0,!0):!1,[]),p=h(()=>{let T=u();return a&&(n?e(...n):e()),s.current=setInterval(e,t,...n||[]),!T&&o&&c(!0),s.current},[t,n,o,a,e,u]),f=h(()=>{u()&&o&&c(!1)},[o,u]);return Ee(()=>{if(i)return p(),f},[i,p,f]),o?{isActive:l,start:p,stop:f}:{start:p,stop:f}}import{useEffect as xe}from"react";var At=(e,r={})=>{let{delay:t=1,args:n}=r;xe(()=>{let i=setInterval(e,t,...n||[]);return()=>clearInterval(i)},[t,n,e])};import{useCallback as H,useEffect as Me}from"react";function jt(e,r={}){let{autoplay:t=!0}=r,n=N(e,{autoplay:!1,...r}),{start:i,stop:a}=n,o=H(()=>document.hidden?a():i(),[i,a]),s=H(()=>{if(document.addEventListener("visibilitychange",o),!document.hidden)return i()},[i,o]),l=H(()=>{a(),document.removeEventListener("visibilitychange",o)},[a,o]);return Me(()=>{if(t)return s(),l},[t,s,l]),{...n,start:s,stop:l}}import{useCallback as D,useEffect as ge,useRef as Se,useState as Oe}from"react";function qt(e,r={}){let{delay:t=1,args:n,autoplay:i=!0,runOnStart:a=!1,updateState:o=!1}=r,s=Se(void 0),[l,c]=Oe(i),u=D(()=>s.current?(clearTimeout(s.current),s.current=void 0,!0):!1,[]),p=D(()=>{let T=u();return a&&(n?e(...n):e()),s.current=setTimeout(()=>{if(s.current=void 0,o&&c(!1),n)return e(...n);e()},t),!T&&o&&c(!0),s.current},[t,n,o,a,e,u]),f=D(()=>{u()&&o&&c(!1)},[o,u]);return ge(()=>{if(i)return p(),f},[i,p,f]),o?{isActive:l,start:p,stop:f}:{start:p,stop:f}}export{et as useDarkMode,Ht as useDebounce,ot as useEventListener,dt as useFocusTrap,yt as useInView,N as useInterval,jt as useIntervalWhenVisible,W as useIsClient,A as useIsFirstRender,ct as useIsPortrait,At as useLightInterval,B as useLightTimeout,K as useLocalStorage,O as useMediaQuery,St as useScrollBlock,Ce as useSessionStorage,S as useStorage,qt as useTimeout,k as useUpdateEffect};
1
+ import{useCallback as w,useEffect as z,useState as G}from"react";import{LocalStorage as V}from"@alessiofrittoli/web-utils/storage/LocalStorage";import{SessionStorage as K}from"@alessiofrittoli/web-utils/storage/SessionStorage";var O=(e,o,t="local")=>{let s=w(()=>(t==="local"?V:K).get(e)??o,[t,e,o]),[i,a]=G(o),r=w(n=>{a(u=>{let l=n instanceof Function?n(u):n;return(typeof window<"u"&&t==="local"?V:K).set(e,l),l})},[t,e]);return z(()=>{a(s())},[s]),[i,r]};var W=(e,o)=>O(e,o,"local");var Ve=(e,o)=>O(e,o,"session");import{useCallback as R,useEffect as Q,useRef as re}from"react";import{useEffect as X}from"react";import{useRef as J}from"react";var S=()=>{let e=J(!0);return e.current?(e.current=!1,!0):e.current};var je=e=>{let o=S();X(()=>{if(o)return e()},[])};import{useEffect as Y,useState as Z}from"react";var U=()=>{let[e,o]=Z(!1);return Y(()=>o(!0),[]),e};import{useEffect as _}from"react";var h=(e,o)=>{let t=S();_(()=>{if(!t)return e()},o)};import{useCallback as ee,useEffect as te,useState as ne}from"react";import{getMediaMatches as A}from"@alessiofrittoli/web-utils/browser-api";function b(e,o={}){let{updateState:t=!0,onChange:s}=o,[i,a]=ne(A(e)),r=ee(()=>{let n=A(e);t&&a(n),s?.(n)},[e,t,s]);if(te(()=>{let n=window.matchMedia(e),{matches:u}=n;return t&&a(u),s?.(u),n.addEventListener("change",r),()=>{n.removeEventListener("change",r)}},[e,t,s,r]),!!t)return i}var it=(e={})=>{let o=U(),t=b("(prefers-color-scheme: dark)"),{initial:s=t,docClassNames:i=[]}=e,[a,r]=W("dark-mode",s),n=a??t,[u,l]=i,c=re({light:"",dark:""});return h(()=>{r(t)},[t,r]),Q(()=>{u&&document.documentElement.classList.toggle(u,n),l&&document.documentElement.classList.toggle(l,!n)},[n,u,l]),Q(()=>{document.head.querySelectorAll('meta[name="theme-color"]').forEach(p=>{let f=p.getAttribute("media"),T=p.getAttribute("content");if(T){if(!f||f==="(prefers-color-scheme: light)"){c.current.light=T;return}c.current.dark=T}})},[]),h(()=>{let p=c.current.dark,f=c.current.light;a&&!p||!a&&!f||document.head.querySelectorAll('meta[name="theme-color"]').forEach(T=>{T.setAttribute("content",a?p:f)})},[a]),{isDarkMode:o?n:!1,isDarkOS:o?t:!1,toggleDarkMode:R(()=>r(p=>!p),[r]),enableDarkMode:R(()=>r(!0),[r]),disableDarkMode:R(()=>r(!1),[r])}};import{useEffect as oe}from"react";function lt(e,o){let{target:t,query:s,options:i,listener:a,onLoad:r,onCleanUp:n}=o;oe(()=>{let u=Array.isArray(e)?e:[e],l=(s?window.matchMedia(s):t&&"current"in t?t.current:t)??window;if(l.addEventListener)return r?.(),u.map(c=>{l.addEventListener(c,a,i)}),()=>{u.map(c=>{l.removeEventListener(c,a,i)}),n?.()}},[e,t,s,i,a,r,n])}import{portraitMediaQuery as se}from"@alessiofrittoli/web-utils/device";var Tt=()=>b(se);import{useCallback as F,useEffect as ie,useRef as ae,useState as ue}from"react";var ce=["input","select","textarea","button","[href]",'[tabindex]:not([tabindex="-1"])'].join(", "),xt=e=>{let[o,t]=ue(!1),s=ae(null),i=F(r=>{s.current=document.activeElement;let n=r||e?.current||!1;if(n)return t(n)},[e]),a=F(()=>{s.current?.focus(),t(!1)},[]);return ie(()=>{if(!o)return;let r=n=>{if(n.key!=="Tab")return;let u=Array.from(o.querySelectorAll(ce)),l=u.at(0),c=u.at(-1);if(!n.shiftKey){document.activeElement===c&&(n.preventDefault(),l?.focus());return}document.activeElement===l&&(n.preventDefault(),c?.focus())};return document.addEventListener("keydown",r),()=>{document.removeEventListener("keydown",r)}},[o]),[i,a]};import{useEffect as le,useMemo as pe,useRef as I,useState as $}from"react";var St=(e,o={})=>{let{initial:t=!1,once:s,amount:i,margin:a,root:r,enable:n=!0}=o,{onEnter:u,onExit:l,onIntersect:c}=o,p=I(!0),[f,T]=$(t),[v,N]=$(n),L=I(null),M=I(!1),x=pe(()=>{if(!v||typeof IntersectionObserver>"u")return;let P=i==="all"?1:i==="some"?.5:i;try{return new IntersectionObserver(async([E],g)=>{if(!E)return;let y=E.isIntersecting;try{if(M.current=!y&&!!L.current,y&&u&&await u({entry:E,observer:g}),M.current&&l&&await l({entry:E,observer:g}),c&&(y||!y&&L.current!=null)){let k={isEntering:y,isExiting:M.current};await c({entry:E,observer:g,...k})}if(L.current=y,!p.current)return;T(y)}catch(k){console.error(k)}y&&s&&g.disconnect()},{root:r||void 0,rootMargin:a,threshold:P})}catch(E){console.error(E)}},[r,a,i,s,v,u,l,c]);return le(()=>{if(p.current=!0,!(!v||!e.current||!x))return x.observe(e.current),()=>{p.current=!1,x.disconnect()}},[e,x,v]),{inView:f,enabled:v,observer:x,isExiting:M.current,setInView:T,setEnabled:N}};import{useCallback as j}from"react";import{blockScroll as me,restoreScroll as de}from"@alessiofrittoli/web-utils/dom";var Rt=e=>{let o=j(()=>me(e?.current||void 0),[e]),t=j(()=>de(e?.current||void 0),[e]);return[o,t]};import{useMemo as Te,useState as ye}from"react";import{useEffect as fe}from"react";var B=(e,o={})=>{let{delay:t=1,args:s}=o;fe(()=>{let i=setTimeout(e,t,...s||[]);return()=>clearTimeout(i)},[t,s,e])};var Wt=(e,o=500)=>{let[t,s]=ye(e),i=Te(()=>[e],[e]);return B(s,{delay:o,args:i}),t};import{useCallback as H,useEffect as Ee,useRef as ve,useState as xe}from"react";function q(e,o={}){let{delay:t=1,args:s,autoplay:i=!0,runOnStart:a=!1,updateState:r=!1}=o,n=ve(void 0),[u,l]=xe(i),c=H(()=>n.current?(clearInterval(n.current),n.current=void 0,!0):!1,[]),p=H(()=>{let T=c();return a&&(s?e(...s):e()),n.current=setInterval(e,t,...s||[]),!T&&r&&l(!0),n.current},[t,s,r,a,e,c]),f=H(()=>{c()&&r&&l(!1)},[r,c]);return Ee(()=>{if(i)return p(),f},[i,p,f]),r?{isActive:u,start:p,stop:f}:{start:p,stop:f}}import{useEffect as Me}from"react";var Bt=(e,o={})=>{let{delay:t=1,args:s}=o;Me(()=>{let i=setInterval(e,t,...s||[]);return()=>clearInterval(i)},[t,s,e])};import{useCallback as C,useEffect as ge}from"react";function Gt(e,o={}){let{autoplay:t=!0}=o,s=q(e,{autoplay:!1,...o}),{start:i,stop:a}=s,r=C(()=>document.hidden?a():i(),[i,a]),n=C(()=>{if(document.addEventListener("visibilitychange",r),!document.hidden)return i()},[i,r]),u=C(()=>{a(),document.removeEventListener("visibilitychange",r)},[a,r]);return ge(()=>{if(t)return n(),u},[t,n,u]),{...s,start:n,stop:u}}import{useCallback as D,useEffect as Oe,useRef as Se,useState as be}from"react";function Zt(e,o={}){let{delay:t=1,args:s,autoplay:i=!0,runOnStart:a=!1,updateState:r=!1}=o,n=Se(void 0),[u,l]=be(i),c=D(()=>n.current?(clearTimeout(n.current),n.current=void 0,!0):!1,[]),p=D(()=>{let T=c();return a&&(s?e(...s):e()),n.current=setTimeout(()=>{if(n.current=void 0,r&&l(!1),s)return e(...s);e()},t),!T&&r&&l(!0),n.current},[t,s,r,a,e,c]),f=D(()=>{c()&&r&&l(!1)},[r,c]);return Oe(()=>{if(i)return p(),f},[i,p,f]),r?{isActive:u,start:p,stop:f}:{start:p,stop:f}}export{it as useDarkMode,Wt as useDebounce,je as useEffectOnce,lt as useEventListener,xt as useFocusTrap,St as useInView,q as useInterval,Gt as useIntervalWhenVisible,U as useIsClient,S as useIsFirstRender,Tt as useIsPortrait,Bt as useLightInterval,B as useLightTimeout,W as useLocalStorage,b as useMediaQuery,Rt as useScrollBlock,Ve as useSessionStorage,O as useStorage,Zt as useTimeout,h as useUpdateEffect};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alessiofrittoli/react-hooks",
3
- "version": "3.0.0",
3
+ "version": "3.2.0-alpha.1",
4
4
  "description": "TypeScript React utility Hooks",
5
5
  "author": {
6
6
  "name": "Alessio Frittoli",
@@ -87,48 +87,42 @@
87
87
  "test:misc": "pnpm test:watch misc/*",
88
88
  "test:timers": "pnpm test:watch timers/*"
89
89
  },
90
- "pnpm": {
91
- "onlyBuiltDependencies": [
92
- "@alessiofrittoli/type-utils",
93
- "esbuild"
94
- ]
95
- },
96
90
  "devDependencies": {
97
- "@alessiofrittoli/event-emitter": "^1.4.0",
98
- "@alessiofrittoli/node-scripts": "^2.5.0",
99
- "@eslint/compat": "^1.2.9",
91
+ "@alessiofrittoli/event-emitter": "^1.5.0",
92
+ "@alessiofrittoli/node-scripts": "^2.6.0",
93
+ "@eslint/compat": "^1.3.1",
100
94
  "@eslint/eslintrc": "^3.3.1",
101
- "@eslint/js": "^9.26.0",
102
- "@jest/globals": "^29.7.0",
95
+ "@eslint/js": "^9.30.1",
96
+ "@jest/globals": "^30.0.4",
103
97
  "@testing-library/dom": "^10.4.0",
104
98
  "@testing-library/jest-dom": "^6.6.3",
105
99
  "@testing-library/react": "^16.3.0",
106
100
  "@testing-library/user-event": "^14.6.1",
107
- "@types/jest": "^29.5.14",
108
- "@types/node": "^22.15.18",
109
- "@types/react": "^19.1.4",
110
- "@types/react-dom": "^19.1.5",
111
- "concurrently": "^9.1.2",
112
- "dotenv": "^16.5.0",
113
- "eslint": "^9.26.0",
101
+ "@types/jest": "^30.0.0",
102
+ "@types/node": "^24.0.10",
103
+ "@types/react": "^19.1.8",
104
+ "@types/react-dom": "^19.1.6",
105
+ "concurrently": "^9.2.0",
106
+ "dotenv": "^17.1.0",
107
+ "eslint": "^9.30.1",
114
108
  "eslint-plugin-react": "^7.37.5",
115
109
  "eslint-plugin-react-hooks": "^5.2.0",
116
- "globals": "^16.1.0",
110
+ "globals": "^16.3.0",
117
111
  "http-server": "^14.1.1",
118
- "jest": "^29.7.0",
119
- "jest-environment-jsdom": "^29.7.0",
112
+ "jest": "^30.0.4",
113
+ "jest-environment-jsdom": "^30.0.4",
120
114
  "react": "^19.1.0",
121
115
  "react-dom": "^19.1.0",
122
- "ts-jest": "^29.3.3",
116
+ "ts-jest": "^29.4.0",
123
117
  "ts-node": "^10.9.2",
124
- "tsup": "^8.4.0",
118
+ "tsup": "^8.5.0",
125
119
  "typescript": "^5.8.3",
126
- "typescript-eslint": "^8.32.1"
120
+ "typescript-eslint": "^8.36.0"
127
121
  },
128
122
  "dependencies": {
129
- "@alessiofrittoli/math-utils": "^1.13.0",
123
+ "@alessiofrittoli/math-utils": "^1.14.0",
130
124
  "@alessiofrittoli/type-utils": "^1.8.0",
131
- "@alessiofrittoli/web-utils": "^1.10.0"
125
+ "@alessiofrittoli/web-utils": "^1.12.0"
132
126
  },
133
127
  "peerDependencies": {
134
128
  "@types/react": "^19",