@studiocubics/hooks 0.0.1 → 0.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.
Files changed (51) hide show
  1. package/dist/index.js +2 -0
  2. package/dist/index.js.map +1 -0
  3. package/dist/useAnchorElement/useAnchorElement.d.ts +8 -0
  4. package/dist/useAnchorElement/useAnchorElement.js +2 -0
  5. package/dist/useAnchorElement/useAnchorElement.js.map +1 -0
  6. package/dist/useDelayedAction/useDelayedAction.d.ts +1 -0
  7. package/dist/useDelayedAction/useDelayedAction.js +2 -0
  8. package/dist/useDelayedAction/useDelayedAction.js.map +1 -0
  9. package/dist/useDisclosure/useDisclosure.d.ts +7 -0
  10. package/dist/useDisclosure/useDisclosure.js +2 -0
  11. package/dist/useDisclosure/useDisclosure.js.map +1 -0
  12. package/dist/useEventCallback/useEventCallback.d.ts +2 -0
  13. package/dist/useEventCallback/useEventCallback.js +2 -0
  14. package/dist/useEventCallback/useEventCallback.js.map +1 -0
  15. package/dist/useEventListener/useEventListener.d.ts +6 -0
  16. package/dist/useEventListener/useEventListener.js +2 -0
  17. package/dist/useEventListener/useEventListener.js.map +1 -0
  18. package/dist/useFormHelpers/useFormHelpers.d.ts +10 -0
  19. package/dist/useFormHelpers/useFormHelpers.js +2 -0
  20. package/dist/useFormHelpers/useFormHelpers.js.map +1 -0
  21. package/dist/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.d.ts +2 -0
  22. package/dist/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js +2 -0
  23. package/dist/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js.map +1 -0
  24. package/dist/useLocalStorage/useLocalStorage.d.ts +13 -0
  25. package/dist/useLocalStorage/useLocalStorage.js +2 -0
  26. package/dist/useLocalStorage/useLocalStorage.js.map +1 -0
  27. package/dist/useMounted/useMounted.d.ts +3 -0
  28. package/dist/useMounted/useMounted.js +2 -0
  29. package/dist/useMounted/useMounted.js.map +1 -0
  30. package/dist/useMousePosition/useMousePosition.d.ts +12 -0
  31. package/dist/useMousePosition/useMousePosition.js +2 -0
  32. package/dist/useMousePosition/useMousePosition.js.map +1 -0
  33. package/dist/useScreenSize/useScreenSize.d.ts +17 -0
  34. package/dist/useScreenSize/useScreenSize.js +2 -0
  35. package/dist/useScreenSize/useScreenSize.js.map +1 -0
  36. package/package.json +6 -6
  37. package/CHANGELOG.md +0 -9
  38. package/eslint.config.js +0 -21
  39. package/src/useAnchorElement/useAnchorElement.tsx +0 -15
  40. package/src/useDelayedAction/useDelayedAction.tsx +0 -12
  41. package/src/useDisclosure/useDisclosure.tsx +0 -36
  42. package/src/useEventCallback/useEventCallback.tsx +0 -26
  43. package/src/useEventListener/useEventListener.tsx +0 -92
  44. package/src/useFormHelpers/useFormHelpers.tsx +0 -29
  45. package/src/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.tsx +0 -6
  46. package/src/useLocalStorage/useLocalStorage.tsx +0 -165
  47. package/src/useMounted/useMounted.tsx +0 -11
  48. package/src/useMousePosition/useMousePosition.tsx +0 -60
  49. package/src/useScreenSize/useScreenSize.tsx +0 -74
  50. package/tsconfig.json +0 -31
  51. /package/{src/index.ts → dist/index.d.ts} +0 -0
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export{useAnchorElement}from"./useAnchorElement/useAnchorElement.js";export{useDelayedAction}from"./useDelayedAction/useDelayedAction.js";export{useDisclosure}from"./useDisclosure/useDisclosure.js";export{useEventCallback}from"./useEventCallback/useEventCallback.js";export{useEventListener}from"./useEventListener/useEventListener.js";export{useFormHelpers}from"./useFormHelpers/useFormHelpers.js";export{useIsomorphicLayoutEffect}from"./useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js";export{useLocalStorage}from"./useLocalStorage/useLocalStorage.js";export{useMounted}from"./useMounted/useMounted.js";export{useMousePosition}from"./useMousePosition/useMousePosition.js";export{useScreenSize}from"./useScreenSize/useScreenSize.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ import { type MouseEvent } from "react";
2
+ export declare function useAnchorElement<T extends HTMLElement>(): {
3
+ open: boolean;
4
+ anchorEl: T | null;
5
+ handleClick: (event: MouseEvent<T>) => void;
6
+ handleClose: () => void;
7
+ setAnchorEl: import("react").Dispatch<import("react").SetStateAction<T | null>>;
8
+ };
@@ -0,0 +1,2 @@
1
+ "use client";import{useState as n,useMemo as e}from"react";function l(){const[l,o]=n(null);return{open:e(()=>Boolean(l),[l]),anchorEl:l,handleClick:n=>{o(n.currentTarget)},handleClose:()=>{o(null)},setAnchorEl:o}}export{l as useAnchorElement};
2
+ //# sourceMappingURL=useAnchorElement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAnchorElement.js","sources":["../../src/useAnchorElement/useAnchorElement.tsx"],"sourcesContent":["\"use client\";\n\nimport { type MouseEvent, useMemo, useState } from \"react\";\n\nexport function useAnchorElement<T extends HTMLElement>() {\n const [anchorEl, setAnchorEl] = useState<T | null>(null);\n const open = useMemo(() => Boolean(anchorEl), [anchorEl]);\n const handleClick = (event: MouseEvent<T>) => {\n setAnchorEl(event.currentTarget);\n };\n const handleClose = () => {\n setAnchorEl(null);\n };\n return { open, anchorEl, handleClick, handleClose, setAnchorEl };\n}\n"],"names":["useAnchorElement","anchorEl","setAnchorEl","useState","open","useMemo","Boolean","handleClick","event","currentTarget","handleClose"],"mappings":"oEAIgBA,IACd,MAAOC,EAAUC,GAAeC,EAAmB,MAQnD,MAAO,CAAEC,KAPIC,EAAQ,IAAMC,QAAQL,GAAW,CAACA,IAOhCA,WAAUM,YANJC,IACnBN,EAAYM,EAAMC,gBAKkBC,YAHlB,KAClBR,EAAY,OAEqCA,cACrD"}
@@ -0,0 +1 @@
1
+ export declare function useDelayedAction(): (fn: Function, ms: number) => Promise<void>;
@@ -0,0 +1,2 @@
1
+ "use client";import{useCallback as e}from"react";function t(){return e(async(e,t)=>{await new Promise(e=>setTimeout(e,t)),e()},[])}export{t as useDelayedAction};
2
+ //# sourceMappingURL=useDelayedAction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDelayedAction.js","sources":["../../src/useDelayedAction/useDelayedAction.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback } from \"react\";\n\nexport function useDelayedAction() {\n const delayedExecute = useCallback(async (fn: Function, ms: number) => {\n await new Promise((resolve) => setTimeout(resolve, ms));\n fn();\n }, []);\n\n return delayedExecute;\n}\n"],"names":["useDelayedAction","useCallback","async","fn","ms","Promise","resolve","setTimeout"],"mappings":"0DAIgBA,IAMd,OALuBC,EAAYC,MAAOC,EAAcC,WAChD,IAAIC,QAASC,GAAYC,WAAWD,EAASF,IACnDD,KACC,GAGL"}
@@ -0,0 +1,7 @@
1
+ export declare function useDisclosure(initialState?: boolean): {
2
+ open: boolean;
3
+ handleClose: () => void;
4
+ handleStrictClose: (_: {}, reason: "backdropClick" | "escapeKeyDown") => void;
5
+ handleOpen: () => void;
6
+ handleToggle: () => void;
7
+ };
@@ -0,0 +1,2 @@
1
+ "use client";import{useState as n}from"react";function e(e=!1){const[o,t]=n(e);function c(){t(!1)}return{open:o,handleClose:c,handleStrictClose:function(n,e){"backdropClick"!==e&&"escapeKeyDown"!==e&&c()},handleOpen:function(){t(!0)},handleToggle:function(){t(n=>!n)}}}export{e as useDisclosure};
2
+ //# sourceMappingURL=useDisclosure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDisclosure.js","sources":["../../src/useDisclosure/useDisclosure.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\n\nexport function useDisclosure(initialState: boolean = false) {\n const [open, setOpen] = useState(initialState);\n\n function handleOpen() {\n setOpen(true);\n }\n function handleClose() {\n setOpen(false);\n }\n\n /**\n * Hijacking the handleClose function to prevent the dialog from closing when the user clicks outside the dialog or presses the escape key.\n * @param _ event not going to be used.\n * @param reason The reason the dialog was closed.\n */\n function handleStrictClose(_: {}, reason: \"backdropClick\" | \"escapeKeyDown\") {\n if (reason === \"backdropClick\" || reason === \"escapeKeyDown\") return;\n handleClose();\n }\n\n function handleToggle() {\n setOpen((prev) => !prev);\n }\n\n return {\n open,\n handleClose,\n handleStrictClose,\n handleOpen,\n handleToggle,\n };\n}\n"],"names":["useDisclosure","initialState","open","setOpen","useState","handleClose","handleStrictClose","_","reason","handleOpen","handleToggle","prev"],"mappings":"8CAIM,SAAUA,EAAcC,GAAwB,GACpD,MAAOC,EAAMC,GAAWC,EAASH,GAKjC,SAASI,IACPF,GAAQ,EACV,CAgBA,MAAO,CACLD,OACAG,cACAC,kBAZF,SAA2BC,EAAOC,GACjB,kBAAXA,GAAyC,kBAAXA,GAClCH,GACF,EAUEI,WAzBF,WACEN,GAAQ,EACV,EAwBEO,aATF,WACEP,EAASQ,IAAUA,EACrB,EASF"}
@@ -0,0 +1,2 @@
1
+ export declare function useEventCallback<Args extends unknown[], R>(fn: (...args: Args) => R): (...args: Args) => R;
2
+ export declare function useEventCallback<Args extends unknown[], R>(fn: ((...args: Args) => R) | undefined): ((...args: Args) => R) | undefined;
@@ -0,0 +1,2 @@
1
+ "use client";import{useRef as r,useCallback as e}from"react";import{useIsomorphicLayoutEffect as t}from"../useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js";function o(o){const n=r(()=>{throw new Error("Cannot call an event handler while rendering.")});return t(()=>{n.current=o},[o]),e((...r)=>n.current?.(...r),[n])}export{o as useEventCallback};
2
+ //# sourceMappingURL=useEventCallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEventCallback.js","sources":["../../src/useEventCallback/useEventCallback.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useRef } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect/useIsomorphicLayoutEffect\";\n\nexport function useEventCallback<Args extends unknown[], R>(\n fn: (...args: Args) => R\n): (...args: Args) => R;\nexport function useEventCallback<Args extends unknown[], R>(\n fn: ((...args: Args) => R) | undefined\n): ((...args: Args) => R) | undefined;\nexport function useEventCallback<Args extends unknown[], R>(\n fn: ((...args: Args) => R) | undefined\n): ((...args: Args) => R) | undefined {\n const ref = useRef<typeof fn>(() => {\n throw new Error(\"Cannot call an event handler while rendering.\");\n });\n\n useIsomorphicLayoutEffect(() => {\n ref.current = fn;\n }, [fn]);\n\n return useCallback((...args: Args) => ref.current?.(...args), [ref]) as (\n ...args: Args\n ) => R;\n}\n"],"names":["useEventCallback","fn","ref","useRef","Error","useIsomorphicLayoutEffect","current","useCallback","args"],"mappings":"mKAWM,SAAUA,EACdC,GAEA,MAAMC,EAAMC,EAAkB,KAC5B,MAAM,IAAIC,MAAM,mDAOlB,OAJAC,EAA0B,KACxBH,EAAII,QAAUL,GACb,CAACA,IAEGM,EAAY,IAAIC,IAAeN,EAAII,aAAaE,GAAO,CAACN,GAGjE"}
@@ -0,0 +1,6 @@
1
+ import type { RefObject } from "react";
2
+ declare function useEventListener<K extends keyof MediaQueryListEventMap>(eventName: K, handler: (event: MediaQueryListEventMap[K]) => void, element: RefObject<MediaQueryList>, options?: boolean | AddEventListenerOptions): void;
3
+ declare function useEventListener<K extends keyof WindowEventMap>(eventName: K, handler: (event: WindowEventMap[K]) => void, element?: undefined, options?: boolean | AddEventListenerOptions): void;
4
+ declare function useEventListener<K extends keyof HTMLElementEventMap & keyof SVGElementEventMap, T extends Element = K extends keyof HTMLElementEventMap ? HTMLDivElement : SVGElement>(eventName: K, handler: ((event: HTMLElementEventMap[K]) => void) | ((event: SVGElementEventMap[K]) => void), element: RefObject<T>, options?: boolean | AddEventListenerOptions): void;
5
+ declare function useEventListener<K extends keyof DocumentEventMap>(eventName: K, handler: (event: DocumentEventMap[K]) => void, element: RefObject<Document>, options?: boolean | AddEventListenerOptions): void;
6
+ export { useEventListener };
@@ -0,0 +1,2 @@
1
+ "use client";import{useRef as e,useEffect as t}from"react";import{useIsomorphicLayoutEffect as r}from"../useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js";function n(n,o,c,s){const i=e(o);r(()=>{i.current=o},[o]),t(()=>{const e=c?.current??window;if(!e||!e.addEventListener)return;const t=e=>{i.current(e)};return e.addEventListener(n,t,s),()=>{e.removeEventListener(n,t,s)}},[n,c,s])}export{n as useEventListener};
2
+ //# sourceMappingURL=useEventListener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEventListener.js","sources":["../../src/useEventListener/useEventListener.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef } from \"react\";\n\nimport type { RefObject } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect/useIsomorphicLayoutEffect\";\n\n// MediaQueryList Event based useEventListener interface\nfunction useEventListener<K extends keyof MediaQueryListEventMap>(\n eventName: K,\n handler: (event: MediaQueryListEventMap[K]) => void,\n element: RefObject<MediaQueryList>,\n options?: boolean | AddEventListenerOptions,\n): void;\n\n// Window Event based useEventListener interface\nfunction useEventListener<K extends keyof WindowEventMap>(\n eventName: K,\n handler: (event: WindowEventMap[K]) => void,\n element?: undefined,\n options?: boolean | AddEventListenerOptions,\n): void;\n\n// Element Event based useEventListener interface\nfunction useEventListener<\n K extends keyof HTMLElementEventMap & keyof SVGElementEventMap,\n T extends Element = K extends keyof HTMLElementEventMap\n ? HTMLDivElement\n : SVGElement,\n>(\n eventName: K,\n handler:\n | ((event: HTMLElementEventMap[K]) => void)\n | ((event: SVGElementEventMap[K]) => void),\n element: RefObject<T>,\n options?: boolean | AddEventListenerOptions,\n): void;\n\n// Document Event based useEventListener interface\nfunction useEventListener<K extends keyof DocumentEventMap>(\n eventName: K,\n handler: (event: DocumentEventMap[K]) => void,\n element: RefObject<Document>,\n options?: boolean | AddEventListenerOptions,\n): void;\n\nfunction useEventListener<\n KW extends keyof WindowEventMap,\n KH extends keyof HTMLElementEventMap & keyof SVGElementEventMap,\n KM extends keyof MediaQueryListEventMap,\n T extends HTMLElement | SVGAElement | MediaQueryList = HTMLElement,\n>(\n eventName: KW | KH | KM,\n handler: (\n event:\n | WindowEventMap[KW]\n | HTMLElementEventMap[KH]\n | SVGElementEventMap[KH]\n | MediaQueryListEventMap[KM]\n | Event,\n ) => void,\n element?: RefObject<T>,\n options?: boolean | AddEventListenerOptions,\n) {\n // Create a ref that stores handler\n const savedHandler = useRef(handler);\n\n useIsomorphicLayoutEffect(() => {\n savedHandler.current = handler;\n }, [handler]);\n\n useEffect(() => {\n // Define the listening target\n const targetElement: T | Window = element?.current ?? window;\n\n if (!(targetElement && targetElement.addEventListener)) return;\n\n // Create event listener that calls handler function stored in ref\n const listener: typeof handler = (event) => {\n savedHandler.current(event);\n };\n\n targetElement.addEventListener(eventName, listener, options);\n\n // Remove event listener on cleanup\n return () => {\n targetElement.removeEventListener(eventName, listener, options);\n };\n }, [eventName, element, options]);\n}\n\nexport { useEventListener };\n"],"names":["useEventListener","eventName","handler","element","options","savedHandler","useRef","useIsomorphicLayoutEffect","current","useEffect","targetElement","window","addEventListener","listener","event","removeEventListener"],"mappings":"iKA8CA,SAASA,EAMPC,EACAC,EAQAC,EACAC,GAGA,MAAMC,EAAeC,EAAOJ,GAE5BK,EAA0B,KACxBF,EAAaG,QAAUN,GACtB,CAACA,IAEJO,EAAU,KAER,MAAMC,EAA4BP,GAASK,SAAWG,OAEtD,IAAMD,IAAiBA,EAAcE,iBAAmB,OAGxD,MAAMC,EAA4BC,IAChCT,EAAaG,QAAQM,IAMvB,OAHAJ,EAAcE,iBAAiBX,EAAWY,EAAUT,GAG7C,KACLM,EAAcK,oBAAoBd,EAAWY,EAAUT,KAExD,CAACH,EAAWE,EAASC,GAC1B"}
@@ -0,0 +1,10 @@
1
+ export type FormHelpersProps = {
2
+ initialLoading?: boolean;
3
+ initialError?: string | unknown;
4
+ };
5
+ export declare function useFormHelpers(props: FormHelpersProps): {
6
+ loading: boolean;
7
+ error: {};
8
+ handleLoading: (l: boolean) => void;
9
+ handleError: (e: string | unknown) => void;
10
+ };
@@ -0,0 +1,2 @@
1
+ "use client";import{useState as r}from"react";function n(n){const[o,i]=r(n?.initialLoading??!1),[e,t]=r(n?.initialError??"");return{loading:o,error:e,handleLoading:function(r){i(r)},handleError:function(r){"string"==typeof r&&t(r),r instanceof Error&&t(r.message),console.error(r)}}}export{n as useFormHelpers};
2
+ //# sourceMappingURL=useFormHelpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFormHelpers.js","sources":["../../src/useFormHelpers/useFormHelpers.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\n\nexport type FormHelpersProps = {\n initialLoading?: boolean;\n initialError?: string | unknown;\n};\n\nexport function useFormHelpers(props: FormHelpersProps) {\n const [loading, setLoading] = useState(props?.initialLoading ?? false);\n const [error, setError] = useState(props?.initialError ?? \"\");\n\n function handleLoading(l: boolean) {\n setLoading(l);\n }\n function handleError(e: string | unknown) {\n if (typeof e === \"string\") setError(e);\n if (e instanceof Error) setError(e.message);\n console.error(e);\n }\n\n return {\n loading,\n error,\n handleLoading,\n handleError,\n };\n}\n"],"names":["useFormHelpers","props","loading","setLoading","useState","initialLoading","error","setError","initialError","handleLoading","l","handleError","e","Error","message","console"],"mappings":"8CASM,SAAUA,EAAeC,GAC7B,MAAOC,EAASC,GAAcC,EAASH,GAAOI,iBAAkB,IACzDC,EAAOC,GAAYH,EAASH,GAAOO,cAAgB,IAW1D,MAAO,CACLN,UACAI,QACAG,cAZF,SAAuBC,GACrBP,EAAWO,EACb,EAWEC,YAVF,SAAqBC,GACF,iBAANA,GAAgBL,EAASK,GAChCA,aAAaC,OAAON,EAASK,EAAEE,SACnCC,QAAQT,MAAMM,EAChB,EAQF"}
@@ -0,0 +1,2 @@
1
+ import { useLayoutEffect } from "react";
2
+ export declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
@@ -0,0 +1,2 @@
1
+ "use client";import{useLayoutEffect as e,useEffect as o}from"react";const t="undefined"!=typeof window?e:o;export{t as useIsomorphicLayoutEffect};
2
+ //# sourceMappingURL=useIsomorphicLayoutEffect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useIsomorphicLayoutEffect.js","sources":["../../src/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useLayoutEffect } from \"react\";\n\nexport const useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n"],"names":["useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect"],"mappings":"oEAIO,MAAMA,EACO,oBAAXC,OAAyBC,EAAkBC"}
@@ -0,0 +1,13 @@
1
+ import type { Dispatch, SetStateAction } from "react";
2
+ declare global {
3
+ interface WindowEventMap {
4
+ "local-storage": CustomEvent;
5
+ }
6
+ }
7
+ type UseLocalStorageOptions<T> = {
8
+ serializer?: (value: T) => string;
9
+ deserializer?: (value: string) => T;
10
+ initializeWithValue?: boolean;
11
+ };
12
+ export declare function useLocalStorage<T>(key: string, initialValue: T | (() => T), options?: UseLocalStorageOptions<T>): [T, Dispatch<SetStateAction<T>>, () => void];
13
+ export {};
@@ -0,0 +1,2 @@
1
+ "use client";import{useCallback as e,useState as n,useEffect as t}from"react";import{useEventCallback as o}from"../useEventCallback/useEventCallback.js";import{useEventListener as r}from"../useEventListener/useEventListener.js";const i="undefined"==typeof window;function a(a,c,s={}){const{initializeWithValue:l=!0}=s,u=e(e=>s.serializer?s.serializer(e):JSON.stringify(e),[s]),g=e(e=>{if(s.deserializer)return s.deserializer(e);if("undefined"===e)return;const n=c instanceof Function?c():c;let t;try{t=JSON.parse(e)}catch(e){return console.error("Error parsing JSON:",e),n}return t},[s,c]),w=e(()=>{const e=c instanceof Function?c():c;if(i)return e;try{const n=window.localStorage.getItem(a);return n?g(n):e}catch(n){return console.warn(`Error reading localStorage key “${a}”:`,n),e}},[c,a,g]),[d,f]=n(()=>l?w():c instanceof Function?c():c),v=o(e=>{i&&console.warn(`Tried setting localStorage key “${a}” even though environment is not a client`);try{const n=e instanceof Function?e(w()):e;window.localStorage.setItem(a,u(n)),f(n),window.dispatchEvent(new StorageEvent("local-storage",{key:a}))}catch(e){console.warn(`Error setting localStorage key “${a}”:`,e)}}),m=o(()=>{i&&console.warn(`Tried removing localStorage key “${a}” even though environment is not a client`);const e=c instanceof Function?c():c;window.localStorage.removeItem(a),f(e),window.dispatchEvent(new StorageEvent("local-storage",{key:a}))});t(()=>{f(w())},[a]);const y=e(e=>{e.key&&e.key!==a||f(w())},[a,w]);return r("storage",y),r("local-storage",y),[d,v,m]}export{a as useLocalStorage};
2
+ //# sourceMappingURL=useLocalStorage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLocalStorage.js","sources":["../../src/useLocalStorage/useLocalStorage.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport type { Dispatch, SetStateAction } from \"react\";\nimport { useEventCallback } from \"../useEventCallback/useEventCallback\";\nimport { useEventListener } from \"../useEventListener/useEventListener\";\n\ndeclare global {\n interface WindowEventMap {\n \"local-storage\": CustomEvent;\n }\n}\n\ntype UseLocalStorageOptions<T> = {\n serializer?: (value: T) => string;\n deserializer?: (value: string) => T;\n initializeWithValue?: boolean;\n};\n\nconst IS_SERVER = typeof window === \"undefined\";\n\nexport function useLocalStorage<T>(\n key: string,\n initialValue: T | (() => T),\n options: UseLocalStorageOptions<T> = {},\n): [T, Dispatch<SetStateAction<T>>, () => void] {\n const { initializeWithValue = true } = options;\n\n const serializer = useCallback<(value: T) => string>(\n (value) => {\n if (options.serializer) {\n return options.serializer(value);\n }\n\n return JSON.stringify(value);\n },\n [options],\n );\n\n const deserializer = useCallback<(value: string) => T>(\n (value) => {\n if (options.deserializer) {\n return options.deserializer(value);\n }\n // Support 'undefined' as a value\n if (value === \"undefined\") {\n return undefined as unknown as T;\n }\n\n const defaultValue =\n initialValue instanceof Function ? initialValue() : initialValue;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(value);\n } catch (error) {\n console.error(\"Error parsing JSON:\", error);\n return defaultValue; // Return initialValue if parsing fails\n }\n\n return parsed as T;\n },\n [options, initialValue],\n );\n\n // Get from local storage then\n // parse stored json or return initialValue\n const readValue = useCallback((): T => {\n const initialValueToUse =\n initialValue instanceof Function ? initialValue() : initialValue;\n\n // Prevent build error \"window is undefined\" but keep working\n if (IS_SERVER) {\n return initialValueToUse;\n }\n\n try {\n const raw = window.localStorage.getItem(key);\n return raw ? deserializer(raw) : initialValueToUse;\n } catch (error) {\n console.warn(`Error reading localStorage key “${key}”:`, error);\n return initialValueToUse;\n }\n }, [initialValue, key, deserializer]);\n\n const [storedValue, setStoredValue] = useState(() => {\n if (initializeWithValue) {\n return readValue();\n }\n\n return initialValue instanceof Function ? initialValue() : initialValue;\n });\n\n // Return a wrapped version of useState's setter function that ...\n // ... persists the new value to localStorage.\n const setValue: Dispatch<SetStateAction<T>> = useEventCallback((value) => {\n // Prevent build error \"window is undefined\" but keeps working\n if (IS_SERVER) {\n console.warn(\n `Tried setting localStorage key “${key}” even though environment is not a client`,\n );\n }\n\n try {\n // Allow value to be a function so we have the same API as useState\n const newValue = value instanceof Function ? value(readValue()) : value;\n\n // Save to local storage\n window.localStorage.setItem(key, serializer(newValue));\n\n // Save state\n setStoredValue(newValue);\n\n // We dispatch a custom event so every similar useLocalStorage hook is notified\n window.dispatchEvent(new StorageEvent(\"local-storage\", { key }));\n } catch (error) {\n console.warn(`Error setting localStorage key “${key}”:`, error);\n }\n });\n\n const removeValue = useEventCallback(() => {\n // Prevent build error \"window is undefined\" but keeps working\n if (IS_SERVER) {\n console.warn(\n `Tried removing localStorage key “${key}” even though environment is not a client`,\n );\n }\n\n const defaultValue =\n initialValue instanceof Function ? initialValue() : initialValue;\n\n // Remove the key from local storage\n window.localStorage.removeItem(key);\n\n // Save state with default value\n setStoredValue(defaultValue);\n\n // We dispatch a custom event so every similar useLocalStorage hook is notified\n window.dispatchEvent(new StorageEvent(\"local-storage\", { key }));\n });\n\n useEffect(() => {\n setStoredValue(readValue());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key]);\n\n const handleStorageChange = useCallback(\n (event: StorageEvent | CustomEvent) => {\n if ((event as StorageEvent).key && (event as StorageEvent).key !== key) {\n return;\n }\n setStoredValue(readValue());\n },\n [key, readValue],\n );\n\n // this only works for other documents, not the current one\n useEventListener(\"storage\", handleStorageChange);\n\n // this is a custom event, triggered in writeValueToLocalStorage\n // See: useLocalStorage()\n useEventListener(\"local-storage\", handleStorageChange);\n\n return [storedValue, setValue, removeValue];\n}\n"],"names":["IS_SERVER","window","useLocalStorage","key","initialValue","options","initializeWithValue","serializer","useCallback","value","JSON","stringify","deserializer","defaultValue","Function","parsed","parse","error","console","readValue","initialValueToUse","raw","localStorage","getItem","warn","storedValue","setStoredValue","useState","setValue","useEventCallback","newValue","setItem","dispatchEvent","StorageEvent","removeValue","removeItem","useEffect","handleStorageChange","event","useEventListener"],"mappings":"oOAmBA,MAAMA,EAA8B,oBAAXC,OAEnB,SAAUC,EACdC,EACAC,EACAC,EAAqC,CAAA,GAErC,MAAMC,oBAAEA,GAAsB,GAASD,EAEjCE,EAAaC,EAChBC,GACKJ,EAAQE,WACHF,EAAQE,WAAWE,GAGrBC,KAAKC,UAAUF,GAExB,CAACJ,IAGGO,EAAeJ,EAClBC,IACC,GAAIJ,EAAQO,aACV,OAAOP,EAAQO,aAAaH,GAG9B,GAAc,cAAVA,EACF,OAGF,MAAMI,EACJT,aAAwBU,SAAWV,IAAiBA,EAEtD,IAAIW,EACJ,IACEA,EAASL,KAAKM,MAAMP,EACtB,CAAE,MAAOQ,GAEP,OADAC,QAAQD,MAAM,sBAAuBA,GAC9BJ,CACT,CAEA,OAAOE,GAET,CAACV,EAASD,IAKNe,EAAYX,EAAY,KAC5B,MAAMY,EACJhB,aAAwBU,SAAWV,IAAiBA,EAGtD,GAAIJ,EACF,OAAOoB,EAGT,IACE,MAAMC,EAAMpB,OAAOqB,aAAaC,QAAQpB,GACxC,OAAOkB,EAAMT,EAAaS,GAAOD,CACnC,CAAE,MAAOH,GAEP,OADAC,QAAQM,KAAK,mCAAmCrB,MAASc,GAClDG,CACT,GACC,CAAChB,EAAcD,EAAKS,KAEhBa,EAAaC,GAAkBC,EAAS,IACzCrB,EACKa,IAGFf,aAAwBU,SAAWV,IAAiBA,GAKvDwB,EAAwCC,EAAkBpB,IAE1DT,GACFkB,QAAQM,KACN,mCAAmCrB,8CAIvC,IAEE,MAAM2B,EAAWrB,aAAiBK,SAAWL,EAAMU,KAAeV,EAGlER,OAAOqB,aAAaS,QAAQ5B,EAAKI,EAAWuB,IAG5CJ,EAAeI,GAGf7B,OAAO+B,cAAc,IAAIC,aAAa,gBAAiB,CAAE9B,QAC3D,CAAE,MAAOc,GACPC,QAAQM,KAAK,mCAAmCrB,MAASc,EAC3D,IAGIiB,EAAcL,EAAiB,KAE/B7B,GACFkB,QAAQM,KACN,oCAAoCrB,8CAIxC,MAAMU,EACJT,aAAwBU,SAAWV,IAAiBA,EAGtDH,OAAOqB,aAAaa,WAAWhC,GAG/BuB,EAAeb,GAGfZ,OAAO+B,cAAc,IAAIC,aAAa,gBAAiB,CAAE9B,WAG3DiC,EAAU,KACRV,EAAeP,MAEd,CAAChB,IAEJ,MAAMkC,EAAsB7B,EACzB8B,IACMA,EAAuBnC,KAAQmC,EAAuBnC,MAAQA,GAGnEuB,EAAeP,MAEjB,CAAChB,EAAKgB,IAUR,OANAoB,EAAiB,UAAWF,GAI5BE,EAAiB,gBAAiBF,GAE3B,CAACZ,EAAaG,EAAUM,EACjC"}
@@ -0,0 +1,3 @@
1
+ export declare function useMounted(): {
2
+ mounted: boolean;
3
+ };
@@ -0,0 +1,2 @@
1
+ "use client";import{useState as t,useEffect as e}from"react";function n(){const[n,o]=t(!1);return e(()=>{o(!0)},[]),{mounted:n}}export{n as useMounted};
2
+ //# sourceMappingURL=useMounted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMounted.js","sources":["../../src/useMounted/useMounted.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\nexport function useMounted() {\n const [mounted, setMounted] = useState(false);\n useEffect(() => {\n setMounted(true);\n }, []);\n return { mounted };\n}\n"],"names":["useMounted","mounted","setMounted","useState","useEffect"],"mappings":"sEAIgBA,IACd,MAAOC,EAASC,GAAcC,GAAS,GAIvC,OAHAC,EAAU,KACRF,GAAW,IACV,IACI,CAAED,UACX"}
@@ -0,0 +1,12 @@
1
+ interface PositionMatrix {
2
+ x: number | undefined;
3
+ y: number | undefined;
4
+ }
5
+ export declare function useMousePosition({ includeTouch }: {
6
+ includeTouch: Boolean;
7
+ }): {
8
+ mousePosition: PositionMatrix;
9
+ touchPosition: PositionMatrix;
10
+ mouseSpeed: number;
11
+ };
12
+ export {};
@@ -0,0 +1,2 @@
1
+ "use client";import{useState as e,useEffect as t}from"react";function o({includeTouch:o}){const[n,i]=e({x:void 0,y:void 0}),[c,s]=e({x:void 0,y:void 0}),[r,u]=e(0),[l,v]=e(void 0);return t(()=>{const e=e=>{let t,o;[t,o]=[e.clientX,e.clientY];var n=Math.abs(e.clientX-(l?.clientX?l?.clientX:0)),c=Math.abs(e.clientY-(l?.clientY?l?.clientY:0)),s=Math.sqrt(n*n+c*c),r=Math.round(10*s);u(r),i({x:t,y:o}),v(e)};return window.addEventListener("mousemove",e),()=>{window.removeEventListener("mousemove",e)}},[l]),t(()=>{const e=e=>{let t,o;if(e.touches){const n=e.touches[0];[t,o]=[n.clientX,n.clientY]}s({x:t,y:o})};return()=>{o&&window.removeEventListener("touchmove",e)}},[o]),{mousePosition:n,touchPosition:c,mouseSpeed:r}}export{o as useMousePosition};
2
+ //# sourceMappingURL=useMousePosition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMousePosition.js","sources":["../../src/useMousePosition/useMousePosition.tsx"],"sourcesContent":["\"use client\";\nimport { useEffect, useState } from \"react\";\n\ninterface PositionMatrix {\n x: number | undefined;\n y: number | undefined;\n}\n\ntype Event = MouseEvent | undefined;\n\nexport function useMousePosition({ includeTouch }: { includeTouch: Boolean }) {\n const [mousePosition, setMousePosition] = useState<PositionMatrix>({\n x: undefined,\n y: undefined,\n });\n const [touchPosition, setTouchPosition] = useState<PositionMatrix>({\n x: undefined,\n y: undefined,\n });\n const [mouseSpeed, setMouseSpeed] = useState(0);\n const [prevEvent, setPrevEvent] = useState<Event>(undefined);\n useEffect(() => {\n const updateMousePosition = (currentEvent: MouseEvent) => {\n let x, y;\n [x, y] = [currentEvent.clientX, currentEvent.clientY];\n var movementX = Math.abs(\n currentEvent.clientX - (prevEvent?.clientX ? prevEvent?.clientX : 0)\n );\n var movementY = Math.abs(\n currentEvent.clientY - (prevEvent?.clientY ? prevEvent?.clientY : 0)\n );\n var movement = Math.sqrt(movementX * movementX + movementY * movementY);\n var speed = Math.round(10 * movement);\n setMouseSpeed(speed);\n setMousePosition({ x, y });\n setPrevEvent(currentEvent);\n // console.log(\"prevEvent\", prevEvent?.screenX);\n };\n window.addEventListener(\"mousemove\", updateMousePosition);\n return () => {\n window.removeEventListener(\"mousemove\", updateMousePosition);\n };\n }, [prevEvent]);\n useEffect(() => {\n const updateTouchPosition = (currentEvent: TouchEvent) => {\n let x, y;\n if (currentEvent.touches) {\n const touch = currentEvent.touches[0];\n [x, y] = [touch.clientX, touch.clientY];\n }\n setTouchPosition({ x, y });\n };\n return () => {\n if (includeTouch) {\n window.removeEventListener(\"touchmove\", updateTouchPosition);\n }\n };\n }, [includeTouch]);\n return { mousePosition, touchPosition, mouseSpeed };\n}\n"],"names":["useMousePosition","includeTouch","mousePosition","setMousePosition","useState","x","undefined","y","touchPosition","setTouchPosition","mouseSpeed","setMouseSpeed","prevEvent","setPrevEvent","useEffect","updateMousePosition","currentEvent","clientX","clientY","movementX","Math","abs","movementY","movement","sqrt","speed","round","window","addEventListener","removeEventListener","updateTouchPosition","touches","touch"],"mappings":"6DAUM,SAAUA,GAAiBC,aAAEA,IACjC,MAAOC,EAAeC,GAAoBC,EAAyB,CACjEC,OAAGC,EACHC,OAAGD,KAEEE,EAAeC,GAAoBL,EAAyB,CACjEC,OAAGC,EACHC,OAAGD,KAEEI,EAAYC,GAAiBP,EAAS,IACtCQ,EAAWC,GAAgBT,OAAgBE,GAsClD,OArCAQ,EAAU,KACR,MAAMC,EAAuBC,IAC3B,IAAIX,EAAGE,GACNF,EAAGE,GAAK,CAACS,EAAaC,QAASD,EAAaE,SAC7C,IAAIC,EAAYC,KAAKC,IACnBL,EAAaC,SAAWL,GAAWK,QAAUL,GAAWK,QAAU,IAEhEK,EAAYF,KAAKC,IACnBL,EAAaE,SAAWN,GAAWM,QAAUN,GAAWM,QAAU,IAEhEK,EAAWH,KAAKI,KAAKL,EAAYA,EAAYG,EAAYA,GACzDG,EAAQL,KAAKM,MAAM,GAAKH,GAC5BZ,EAAcc,GACdtB,EAAiB,CAAEE,IAAGE,MACtBM,EAAaG,IAIf,OADAW,OAAOC,iBAAiB,YAAab,GAC9B,KACLY,OAAOE,oBAAoB,YAAad,KAEzC,CAACH,IACJE,EAAU,KACR,MAAMgB,EAAuBd,IAC3B,IAAIX,EAAGE,EACP,GAAIS,EAAae,QAAS,CACxB,MAAMC,EAAQhB,EAAae,QAAQ,IAClC1B,EAAGE,GAAK,CAACyB,EAAMf,QAASe,EAAMd,QACjC,CACAT,EAAiB,CAAEJ,IAAGE,OAExB,MAAO,KACDN,GACF0B,OAAOE,oBAAoB,YAAaC,KAG3C,CAAC7B,IACG,CAAEC,gBAAeM,gBAAeE,aACzC"}
@@ -0,0 +1,17 @@
1
+ type ScreenSize = {
2
+ width: number;
3
+ height: number;
4
+ isSmall: boolean;
5
+ isMedium: boolean;
6
+ isLarge: boolean;
7
+ isXLarge: boolean;
8
+ ltSmall: boolean;
9
+ ltMedium: boolean;
10
+ ltLarge: boolean;
11
+ ltXLarge: boolean;
12
+ gtSmall: boolean;
13
+ gtMedium: boolean;
14
+ gtLarge: boolean;
15
+ } | null;
16
+ export declare function useScreenSize(): Partial<ScreenSize>;
17
+ export {};
@@ -0,0 +1,2 @@
1
+ "use client";import{useState as e,useEffect as t}from"react";import{useLocalStorage as i}from"../useLocalStorage/useLocalStorage.js";const r=Object.freeze({sm:600,md:900,lg:1281,xl:1536});function n(){const[n,s]=i("screen",{width:0,height:0}),[d,o]=e({...n});return t(()=>{const e=n.width,t=n.height;o({width:e,height:t,isSmall:e<r.sm,isMedium:e>=r.sm&&e<r.md,isLarge:e>=r.md&&e<r.lg,isXLarge:e>=r.lg,ltSmall:e<r.sm,ltMedium:e<r.md,ltLarge:e<r.lg,ltXLarge:e<r.xl,gtSmall:e>=r.sm,gtMedium:e>=r.md,gtLarge:e>=r.lg})},[n]),t(()=>{if("undefined"==typeof window)return;const e=()=>{const e=window.innerWidth,t=window.innerHeight;s({width:e,height:t})};return e(),window.addEventListener("resize",e),()=>window.removeEventListener("resize",e)},[]),d}export{n as useScreenSize};
2
+ //# sourceMappingURL=useScreenSize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useScreenSize.js","sources":["../../src/useScreenSize/useScreenSize.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect } from \"react\";\nimport { useLocalStorage } from \"../useLocalStorage/useLocalStorage\";\n\ntype ScreenSize = {\n width: number;\n height: number;\n isSmall: boolean;\n isMedium: boolean;\n isLarge: boolean;\n isXLarge: boolean;\n ltSmall: boolean;\n ltMedium: boolean;\n ltLarge: boolean;\n ltXLarge: boolean;\n gtSmall: boolean;\n gtMedium: boolean;\n gtLarge: boolean;\n} | null;\n\n// Move breakpoints OUTSIDE. Prevents Rollup/minifiers from collapsing them.\nconst BREAKPOINTS = Object.freeze({\n sm: 600,\n md: 900,\n lg: 1281,\n xl: 1536,\n});\n\nexport function useScreenSize(): Partial<ScreenSize> {\n const [screenSize, setScreenSize] = useLocalStorage(\"screen\", {\n width: 0,\n height: 0,\n });\n const [size, setSize] = useState<Partial<ScreenSize>>({ ...screenSize });\n\n useEffect(() => {\n const width = screenSize.width;\n const height = screenSize.height;\n setSize({\n width,\n height,\n isSmall: width < BREAKPOINTS.sm,\n isMedium: width >= BREAKPOINTS.sm && width < BREAKPOINTS.md,\n isLarge: width >= BREAKPOINTS.md && width < BREAKPOINTS.lg,\n isXLarge: width >= BREAKPOINTS.lg,\n\n ltSmall: width < BREAKPOINTS.sm,\n ltMedium: width < BREAKPOINTS.md,\n ltLarge: width < BREAKPOINTS.lg,\n ltXLarge: width < BREAKPOINTS.xl,\n\n gtSmall: width >= BREAKPOINTS.sm,\n gtMedium: width >= BREAKPOINTS.md,\n gtLarge: width >= BREAKPOINTS.lg,\n });\n }, [screenSize]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const compute = () => {\n const width = window.innerWidth;\n const height = window.innerHeight;\n setScreenSize({ width, height });\n };\n\n compute();\n window.addEventListener(\"resize\", compute);\n return () => window.removeEventListener(\"resize\", compute);\n }, []);\n\n return size;\n}\n"],"names":["BREAKPOINTS","Object","freeze","sm","md","lg","xl","useScreenSize","screenSize","setScreenSize","useLocalStorage","width","height","size","setSize","useState","useEffect","isSmall","isMedium","isLarge","isXLarge","ltSmall","ltMedium","ltLarge","ltXLarge","gtSmall","gtMedium","gtLarge","window","compute","innerWidth","innerHeight","addEventListener","removeEventListener"],"mappings":"qIAsBA,MAAMA,EAAcC,OAAOC,OAAO,CAChCC,GAAI,IACJC,GAAI,IACJC,GAAI,KACJC,GAAI,gBAGUC,IACd,MAAOC,EAAYC,GAAiBC,EAAgB,SAAU,CAC5DC,MAAO,EACPC,OAAQ,KAEHC,EAAMC,GAAWC,EAA8B,IAAKP,IAsC3D,OApCAQ,EAAU,KACR,MAAML,EAAQH,EAAWG,MACnBC,EAASJ,EAAWI,OAC1BE,EAAQ,CACNH,QACAC,SACAK,QAASN,EAAQX,EAAYG,GAC7Be,SAAUP,GAASX,EAAYG,IAAMQ,EAAQX,EAAYI,GACzDe,QAASR,GAASX,EAAYI,IAAMO,EAAQX,EAAYK,GACxDe,SAAUT,GAASX,EAAYK,GAE/BgB,QAASV,EAAQX,EAAYG,GAC7BmB,SAAUX,EAAQX,EAAYI,GAC9BmB,QAASZ,EAAQX,EAAYK,GAC7BmB,SAAUb,EAAQX,EAAYM,GAE9BmB,QAASd,GAASX,EAAYG,GAC9BuB,SAAUf,GAASX,EAAYI,GAC/BuB,QAAShB,GAASX,EAAYK,MAE/B,CAACG,IAEJQ,EAAU,KACR,GAAsB,oBAAXY,OAAwB,OAEnC,MAAMC,EAAU,KACd,MAAMlB,EAAQiB,OAAOE,WACflB,EAASgB,OAAOG,YACtBtB,EAAc,CAAEE,QAAOC,YAKzB,OAFAiB,IACAD,OAAOI,iBAAiB,SAAUH,GAC3B,IAAMD,OAAOK,oBAAoB,SAAUJ,IACjD,IAEIhB,CACT"}
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "access": "public"
6
6
  },
7
7
  "private": false,
8
- "version": "0.0.1",
8
+ "version": "0.0.2",
9
9
  "keywords": [
10
10
  "@studiocubics",
11
11
  "cubics",
@@ -26,19 +26,19 @@
26
26
  "./styles.css": "./dist/index.css"
27
27
  },
28
28
  "peerDependencies": {
29
- "react": "^19.2.0",
30
- "react-dom": "^19.2.0"
29
+ "react": "^19.2.4",
30
+ "react-dom": "^19.2.4"
31
31
  },
32
32
  "dependencies": {
33
- "@studiocubics/types": "^0.0.1"
33
+ "@studiocubics/types": "^0.0.2"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@eslint/js": "^9.39.1",
37
37
  "@rollup/plugin-terser": "^0.4.4",
38
38
  "@rollup/plugin-typescript": "^12.3.0",
39
39
  "@types/node": "^24.10.1",
40
- "@types/react": "^19.2.5",
41
- "@types/react-dom": "^19.2.3",
40
+ "@types/react": "^19",
41
+ "@types/react-dom": "^19",
42
42
  "eslint": "^9.39.1",
43
43
  "eslint-plugin-react-hooks": "^7.0.1",
44
44
  "globals": "^16.5.0",
package/CHANGELOG.md DELETED
@@ -1,9 +0,0 @@
1
- # @studiocubics/hooks
2
-
3
- ## 0.0.1
4
-
5
- ### Patch Changes
6
-
7
- - First publish inshallah!
8
- - Updated dependencies
9
- - @studiocubics/types@0.0.1
package/eslint.config.js DELETED
@@ -1,21 +0,0 @@
1
- import js from "@eslint/js";
2
- import globals from "globals";
3
- import reactHooks from "eslint-plugin-react-hooks";
4
- import tseslint from "typescript-eslint";
5
- import { defineConfig, globalIgnores } from "eslint/config";
6
-
7
- export default defineConfig([
8
- globalIgnores(["dist"]),
9
- {
10
- files: ["**/*.{ts,tsx}"],
11
- extends: [
12
- js.configs.recommended,
13
- tseslint.configs.recommended,
14
- reactHooks.configs.flat.recommended,
15
- ],
16
- languageOptions: {
17
- ecmaVersion: 2020,
18
- globals: globals.browser,
19
- },
20
- },
21
- ]);
@@ -1,15 +0,0 @@
1
- "use client";
2
-
3
- import { type MouseEvent, useMemo, useState } from "react";
4
-
5
- export function useAnchorElement<T extends HTMLElement>() {
6
- const [anchorEl, setAnchorEl] = useState<T | null>(null);
7
- const open = useMemo(() => Boolean(anchorEl), [anchorEl]);
8
- const handleClick = (event: MouseEvent<T>) => {
9
- setAnchorEl(event.currentTarget);
10
- };
11
- const handleClose = () => {
12
- setAnchorEl(null);
13
- };
14
- return { open, anchorEl, handleClick, handleClose, setAnchorEl };
15
- }
@@ -1,12 +0,0 @@
1
- "use client";
2
-
3
- import { useCallback } from "react";
4
-
5
- export function useDelayedAction() {
6
- const delayedExecute = useCallback(async (fn: Function, ms: number) => {
7
- await new Promise((resolve) => setTimeout(resolve, ms));
8
- fn();
9
- }, []);
10
-
11
- return delayedExecute;
12
- }
@@ -1,36 +0,0 @@
1
- "use client";
2
-
3
- import { useState } from "react";
4
-
5
- export function useDisclosure(initialState: boolean = false) {
6
- const [open, setOpen] = useState(initialState);
7
-
8
- function handleOpen() {
9
- setOpen(true);
10
- }
11
- function handleClose() {
12
- setOpen(false);
13
- }
14
-
15
- /**
16
- * Hijacking the handleClose function to prevent the dialog from closing when the user clicks outside the dialog or presses the escape key.
17
- * @param _ event not going to be used.
18
- * @param reason The reason the dialog was closed.
19
- */
20
- function handleStrictClose(_: {}, reason: "backdropClick" | "escapeKeyDown") {
21
- if (reason === "backdropClick" || reason === "escapeKeyDown") return;
22
- handleClose();
23
- }
24
-
25
- function handleToggle() {
26
- setOpen((prev) => !prev);
27
- }
28
-
29
- return {
30
- open,
31
- handleClose,
32
- handleStrictClose,
33
- handleOpen,
34
- handleToggle,
35
- };
36
- }
@@ -1,26 +0,0 @@
1
- "use client";
2
-
3
- import { useCallback, useRef } from "react";
4
- import { useIsomorphicLayoutEffect } from "../useIsomorphicLayoutEffect/useIsomorphicLayoutEffect";
5
-
6
- export function useEventCallback<Args extends unknown[], R>(
7
- fn: (...args: Args) => R
8
- ): (...args: Args) => R;
9
- export function useEventCallback<Args extends unknown[], R>(
10
- fn: ((...args: Args) => R) | undefined
11
- ): ((...args: Args) => R) | undefined;
12
- export function useEventCallback<Args extends unknown[], R>(
13
- fn: ((...args: Args) => R) | undefined
14
- ): ((...args: Args) => R) | undefined {
15
- const ref = useRef<typeof fn>(() => {
16
- throw new Error("Cannot call an event handler while rendering.");
17
- });
18
-
19
- useIsomorphicLayoutEffect(() => {
20
- ref.current = fn;
21
- }, [fn]);
22
-
23
- return useCallback((...args: Args) => ref.current?.(...args), [ref]) as (
24
- ...args: Args
25
- ) => R;
26
- }
@@ -1,92 +0,0 @@
1
- "use client";
2
-
3
- import { useEffect, useRef } from "react";
4
-
5
- import type { RefObject } from "react";
6
- import { useIsomorphicLayoutEffect } from "../useIsomorphicLayoutEffect/useIsomorphicLayoutEffect";
7
-
8
- // MediaQueryList Event based useEventListener interface
9
- function useEventListener<K extends keyof MediaQueryListEventMap>(
10
- eventName: K,
11
- handler: (event: MediaQueryListEventMap[K]) => void,
12
- element: RefObject<MediaQueryList>,
13
- options?: boolean | AddEventListenerOptions,
14
- ): void;
15
-
16
- // Window Event based useEventListener interface
17
- function useEventListener<K extends keyof WindowEventMap>(
18
- eventName: K,
19
- handler: (event: WindowEventMap[K]) => void,
20
- element?: undefined,
21
- options?: boolean | AddEventListenerOptions,
22
- ): void;
23
-
24
- // Element Event based useEventListener interface
25
- function useEventListener<
26
- K extends keyof HTMLElementEventMap & keyof SVGElementEventMap,
27
- T extends Element = K extends keyof HTMLElementEventMap
28
- ? HTMLDivElement
29
- : SVGElement,
30
- >(
31
- eventName: K,
32
- handler:
33
- | ((event: HTMLElementEventMap[K]) => void)
34
- | ((event: SVGElementEventMap[K]) => void),
35
- element: RefObject<T>,
36
- options?: boolean | AddEventListenerOptions,
37
- ): void;
38
-
39
- // Document Event based useEventListener interface
40
- function useEventListener<K extends keyof DocumentEventMap>(
41
- eventName: K,
42
- handler: (event: DocumentEventMap[K]) => void,
43
- element: RefObject<Document>,
44
- options?: boolean | AddEventListenerOptions,
45
- ): void;
46
-
47
- function useEventListener<
48
- KW extends keyof WindowEventMap,
49
- KH extends keyof HTMLElementEventMap & keyof SVGElementEventMap,
50
- KM extends keyof MediaQueryListEventMap,
51
- T extends HTMLElement | SVGAElement | MediaQueryList = HTMLElement,
52
- >(
53
- eventName: KW | KH | KM,
54
- handler: (
55
- event:
56
- | WindowEventMap[KW]
57
- | HTMLElementEventMap[KH]
58
- | SVGElementEventMap[KH]
59
- | MediaQueryListEventMap[KM]
60
- | Event,
61
- ) => void,
62
- element?: RefObject<T>,
63
- options?: boolean | AddEventListenerOptions,
64
- ) {
65
- // Create a ref that stores handler
66
- const savedHandler = useRef(handler);
67
-
68
- useIsomorphicLayoutEffect(() => {
69
- savedHandler.current = handler;
70
- }, [handler]);
71
-
72
- useEffect(() => {
73
- // Define the listening target
74
- const targetElement: T | Window = element?.current ?? window;
75
-
76
- if (!(targetElement && targetElement.addEventListener)) return;
77
-
78
- // Create event listener that calls handler function stored in ref
79
- const listener: typeof handler = (event) => {
80
- savedHandler.current(event);
81
- };
82
-
83
- targetElement.addEventListener(eventName, listener, options);
84
-
85
- // Remove event listener on cleanup
86
- return () => {
87
- targetElement.removeEventListener(eventName, listener, options);
88
- };
89
- }, [eventName, element, options]);
90
- }
91
-
92
- export { useEventListener };
@@ -1,29 +0,0 @@
1
- "use client";
2
-
3
- import { useState } from "react";
4
-
5
- export type FormHelpersProps = {
6
- initialLoading?: boolean;
7
- initialError?: string | unknown;
8
- };
9
-
10
- export function useFormHelpers(props: FormHelpersProps) {
11
- const [loading, setLoading] = useState(props?.initialLoading ?? false);
12
- const [error, setError] = useState(props?.initialError ?? "");
13
-
14
- function handleLoading(l: boolean) {
15
- setLoading(l);
16
- }
17
- function handleError(e: string | unknown) {
18
- if (typeof e === "string") setError(e);
19
- if (e instanceof Error) setError(e.message);
20
- console.error(e);
21
- }
22
-
23
- return {
24
- loading,
25
- error,
26
- handleLoading,
27
- handleError,
28
- };
29
- }
@@ -1,6 +0,0 @@
1
- "use client";
2
-
3
- import { useEffect, useLayoutEffect } from "react";
4
-
5
- export const useIsomorphicLayoutEffect =
6
- typeof window !== "undefined" ? useLayoutEffect : useEffect;
@@ -1,165 +0,0 @@
1
- "use client";
2
-
3
- import { useCallback, useEffect, useState } from "react";
4
- import type { Dispatch, SetStateAction } from "react";
5
- import { useEventCallback } from "../useEventCallback/useEventCallback";
6
- import { useEventListener } from "../useEventListener/useEventListener";
7
-
8
- declare global {
9
- interface WindowEventMap {
10
- "local-storage": CustomEvent;
11
- }
12
- }
13
-
14
- type UseLocalStorageOptions<T> = {
15
- serializer?: (value: T) => string;
16
- deserializer?: (value: string) => T;
17
- initializeWithValue?: boolean;
18
- };
19
-
20
- const IS_SERVER = typeof window === "undefined";
21
-
22
- export function useLocalStorage<T>(
23
- key: string,
24
- initialValue: T | (() => T),
25
- options: UseLocalStorageOptions<T> = {},
26
- ): [T, Dispatch<SetStateAction<T>>, () => void] {
27
- const { initializeWithValue = true } = options;
28
-
29
- const serializer = useCallback<(value: T) => string>(
30
- (value) => {
31
- if (options.serializer) {
32
- return options.serializer(value);
33
- }
34
-
35
- return JSON.stringify(value);
36
- },
37
- [options],
38
- );
39
-
40
- const deserializer = useCallback<(value: string) => T>(
41
- (value) => {
42
- if (options.deserializer) {
43
- return options.deserializer(value);
44
- }
45
- // Support 'undefined' as a value
46
- if (value === "undefined") {
47
- return undefined as unknown as T;
48
- }
49
-
50
- const defaultValue =
51
- initialValue instanceof Function ? initialValue() : initialValue;
52
-
53
- let parsed: unknown;
54
- try {
55
- parsed = JSON.parse(value);
56
- } catch (error) {
57
- console.error("Error parsing JSON:", error);
58
- return defaultValue; // Return initialValue if parsing fails
59
- }
60
-
61
- return parsed as T;
62
- },
63
- [options, initialValue],
64
- );
65
-
66
- // Get from local storage then
67
- // parse stored json or return initialValue
68
- const readValue = useCallback((): T => {
69
- const initialValueToUse =
70
- initialValue instanceof Function ? initialValue() : initialValue;
71
-
72
- // Prevent build error "window is undefined" but keep working
73
- if (IS_SERVER) {
74
- return initialValueToUse;
75
- }
76
-
77
- try {
78
- const raw = window.localStorage.getItem(key);
79
- return raw ? deserializer(raw) : initialValueToUse;
80
- } catch (error) {
81
- console.warn(`Error reading localStorage key “${key}”:`, error);
82
- return initialValueToUse;
83
- }
84
- }, [initialValue, key, deserializer]);
85
-
86
- const [storedValue, setStoredValue] = useState(() => {
87
- if (initializeWithValue) {
88
- return readValue();
89
- }
90
-
91
- return initialValue instanceof Function ? initialValue() : initialValue;
92
- });
93
-
94
- // Return a wrapped version of useState's setter function that ...
95
- // ... persists the new value to localStorage.
96
- const setValue: Dispatch<SetStateAction<T>> = useEventCallback((value) => {
97
- // Prevent build error "window is undefined" but keeps working
98
- if (IS_SERVER) {
99
- console.warn(
100
- `Tried setting localStorage key “${key}” even though environment is not a client`,
101
- );
102
- }
103
-
104
- try {
105
- // Allow value to be a function so we have the same API as useState
106
- const newValue = value instanceof Function ? value(readValue()) : value;
107
-
108
- // Save to local storage
109
- window.localStorage.setItem(key, serializer(newValue));
110
-
111
- // Save state
112
- setStoredValue(newValue);
113
-
114
- // We dispatch a custom event so every similar useLocalStorage hook is notified
115
- window.dispatchEvent(new StorageEvent("local-storage", { key }));
116
- } catch (error) {
117
- console.warn(`Error setting localStorage key “${key}”:`, error);
118
- }
119
- });
120
-
121
- const removeValue = useEventCallback(() => {
122
- // Prevent build error "window is undefined" but keeps working
123
- if (IS_SERVER) {
124
- console.warn(
125
- `Tried removing localStorage key “${key}” even though environment is not a client`,
126
- );
127
- }
128
-
129
- const defaultValue =
130
- initialValue instanceof Function ? initialValue() : initialValue;
131
-
132
- // Remove the key from local storage
133
- window.localStorage.removeItem(key);
134
-
135
- // Save state with default value
136
- setStoredValue(defaultValue);
137
-
138
- // We dispatch a custom event so every similar useLocalStorage hook is notified
139
- window.dispatchEvent(new StorageEvent("local-storage", { key }));
140
- });
141
-
142
- useEffect(() => {
143
- setStoredValue(readValue());
144
- // eslint-disable-next-line react-hooks/exhaustive-deps
145
- }, [key]);
146
-
147
- const handleStorageChange = useCallback(
148
- (event: StorageEvent | CustomEvent) => {
149
- if ((event as StorageEvent).key && (event as StorageEvent).key !== key) {
150
- return;
151
- }
152
- setStoredValue(readValue());
153
- },
154
- [key, readValue],
155
- );
156
-
157
- // this only works for other documents, not the current one
158
- useEventListener("storage", handleStorageChange);
159
-
160
- // this is a custom event, triggered in writeValueToLocalStorage
161
- // See: useLocalStorage()
162
- useEventListener("local-storage", handleStorageChange);
163
-
164
- return [storedValue, setValue, removeValue];
165
- }
@@ -1,11 +0,0 @@
1
- "use client";
2
-
3
- import { useEffect, useState } from "react";
4
-
5
- export function useMounted() {
6
- const [mounted, setMounted] = useState(false);
7
- useEffect(() => {
8
- setMounted(true);
9
- }, []);
10
- return { mounted };
11
- }
@@ -1,60 +0,0 @@
1
- "use client";
2
- import { useEffect, useState } from "react";
3
-
4
- interface PositionMatrix {
5
- x: number | undefined;
6
- y: number | undefined;
7
- }
8
-
9
- type Event = MouseEvent | undefined;
10
-
11
- export function useMousePosition({ includeTouch }: { includeTouch: Boolean }) {
12
- const [mousePosition, setMousePosition] = useState<PositionMatrix>({
13
- x: undefined,
14
- y: undefined,
15
- });
16
- const [touchPosition, setTouchPosition] = useState<PositionMatrix>({
17
- x: undefined,
18
- y: undefined,
19
- });
20
- const [mouseSpeed, setMouseSpeed] = useState(0);
21
- const [prevEvent, setPrevEvent] = useState<Event>(undefined);
22
- useEffect(() => {
23
- const updateMousePosition = (currentEvent: MouseEvent) => {
24
- let x, y;
25
- [x, y] = [currentEvent.clientX, currentEvent.clientY];
26
- var movementX = Math.abs(
27
- currentEvent.clientX - (prevEvent?.clientX ? prevEvent?.clientX : 0)
28
- );
29
- var movementY = Math.abs(
30
- currentEvent.clientY - (prevEvent?.clientY ? prevEvent?.clientY : 0)
31
- );
32
- var movement = Math.sqrt(movementX * movementX + movementY * movementY);
33
- var speed = Math.round(10 * movement);
34
- setMouseSpeed(speed);
35
- setMousePosition({ x, y });
36
- setPrevEvent(currentEvent);
37
- // console.log("prevEvent", prevEvent?.screenX);
38
- };
39
- window.addEventListener("mousemove", updateMousePosition);
40
- return () => {
41
- window.removeEventListener("mousemove", updateMousePosition);
42
- };
43
- }, [prevEvent]);
44
- useEffect(() => {
45
- const updateTouchPosition = (currentEvent: TouchEvent) => {
46
- let x, y;
47
- if (currentEvent.touches) {
48
- const touch = currentEvent.touches[0];
49
- [x, y] = [touch.clientX, touch.clientY];
50
- }
51
- setTouchPosition({ x, y });
52
- };
53
- return () => {
54
- if (includeTouch) {
55
- window.removeEventListener("touchmove", updateTouchPosition);
56
- }
57
- };
58
- }, [includeTouch]);
59
- return { mousePosition, touchPosition, mouseSpeed };
60
- }
@@ -1,74 +0,0 @@
1
- "use client";
2
-
3
- import { useState, useEffect } from "react";
4
- import { useLocalStorage } from "../useLocalStorage/useLocalStorage";
5
-
6
- type ScreenSize = {
7
- width: number;
8
- height: number;
9
- isSmall: boolean;
10
- isMedium: boolean;
11
- isLarge: boolean;
12
- isXLarge: boolean;
13
- ltSmall: boolean;
14
- ltMedium: boolean;
15
- ltLarge: boolean;
16
- ltXLarge: boolean;
17
- gtSmall: boolean;
18
- gtMedium: boolean;
19
- gtLarge: boolean;
20
- } | null;
21
-
22
- // Move breakpoints OUTSIDE. Prevents Rollup/minifiers from collapsing them.
23
- const BREAKPOINTS = Object.freeze({
24
- sm: 600,
25
- md: 900,
26
- lg: 1281,
27
- xl: 1536,
28
- });
29
-
30
- export function useScreenSize(): Partial<ScreenSize> {
31
- const [screenSize, setScreenSize] = useLocalStorage("screen", {
32
- width: 0,
33
- height: 0,
34
- });
35
- const [size, setSize] = useState<Partial<ScreenSize>>({ ...screenSize });
36
-
37
- useEffect(() => {
38
- const width = screenSize.width;
39
- const height = screenSize.height;
40
- setSize({
41
- width,
42
- height,
43
- isSmall: width < BREAKPOINTS.sm,
44
- isMedium: width >= BREAKPOINTS.sm && width < BREAKPOINTS.md,
45
- isLarge: width >= BREAKPOINTS.md && width < BREAKPOINTS.lg,
46
- isXLarge: width >= BREAKPOINTS.lg,
47
-
48
- ltSmall: width < BREAKPOINTS.sm,
49
- ltMedium: width < BREAKPOINTS.md,
50
- ltLarge: width < BREAKPOINTS.lg,
51
- ltXLarge: width < BREAKPOINTS.xl,
52
-
53
- gtSmall: width >= BREAKPOINTS.sm,
54
- gtMedium: width >= BREAKPOINTS.md,
55
- gtLarge: width >= BREAKPOINTS.lg,
56
- });
57
- }, [screenSize]);
58
-
59
- useEffect(() => {
60
- if (typeof window === "undefined") return;
61
-
62
- const compute = () => {
63
- const width = window.innerWidth;
64
- const height = window.innerHeight;
65
- setScreenSize({ width, height });
66
- };
67
-
68
- compute();
69
- window.addEventListener("resize", compute);
70
- return () => window.removeEventListener("resize", compute);
71
- }, []);
72
-
73
- return size;
74
- }
package/tsconfig.json DELETED
@@ -1,31 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
- "target": "ES2022",
5
- "useDefineForClassFields": true,
6
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
- "module": "ESNext",
8
- "resolveJsonModule": true,
9
- "allowJs": true,
10
- "skipLibCheck": true,
11
-
12
- /* Bundler mode */
13
- "moduleResolution": "bundler",
14
- "verbatimModuleSyntax": true,
15
- "moduleDetection": "force",
16
- "noEmit": true,
17
- "jsx": "react-jsx",
18
- // Output
19
- "declaration": true,
20
- "outDir": "./dist",
21
-
22
- /* Linting */
23
- "strict": true,
24
- "noUnusedLocals": true,
25
- "noUnusedParameters": true,
26
- "erasableSyntaxOnly": true,
27
- "noFallthroughCasesInSwitch": true,
28
- "noUncheckedSideEffectImports": true
29
- },
30
- "include": ["src"]
31
- }
File without changes