@refraktor/utils 0.0.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.
Files changed (85) hide show
  1. package/.turbo/turbo-build.log +1 -0
  2. package/LICENSE +21 -0
  3. package/README.md +21 -0
  4. package/build/hooks/index.d.ts +9 -0
  5. package/build/hooks/index.d.ts.map +1 -0
  6. package/build/hooks/index.js +8 -0
  7. package/build/hooks/use-click-outside/index.d.ts +5 -0
  8. package/build/hooks/use-click-outside/index.d.ts.map +1 -0
  9. package/build/hooks/use-click-outside/index.js +50 -0
  10. package/build/hooks/use-debounced-callback/index.d.ts +11 -0
  11. package/build/hooks/use-debounced-callback/index.d.ts.map +1 -0
  12. package/build/hooks/use-debounced-callback/index.js +88 -0
  13. package/build/hooks/use-disclosure/index.d.ts +12 -0
  14. package/build/hooks/use-disclosure/index.d.ts.map +1 -0
  15. package/build/hooks/use-disclosure/index.js +39 -0
  16. package/build/hooks/use-id/index.d.ts +2 -0
  17. package/build/hooks/use-id/index.d.ts.map +1 -0
  18. package/build/hooks/use-id/index.js +5 -0
  19. package/build/hooks/use-isomorphic-layout-effect/index.d.ts +3 -0
  20. package/build/hooks/use-isomorphic-layout-effect/index.d.ts.map +1 -0
  21. package/build/hooks/use-isomorphic-layout-effect/index.js +2 -0
  22. package/build/hooks/use-merged-refs/index.d.ts +6 -0
  23. package/build/hooks/use-merged-refs/index.d.ts.map +1 -0
  24. package/build/hooks/use-merged-refs/index.js +38 -0
  25. package/build/hooks/use-resize-observer/index.d.ts +15 -0
  26. package/build/hooks/use-resize-observer/index.d.ts.map +1 -0
  27. package/build/hooks/use-resize-observer/index.js +65 -0
  28. package/build/hooks/use-uncontrolled/index.d.ts +13 -0
  29. package/build/hooks/use-uncontrolled/index.d.ts.map +1 -0
  30. package/build/hooks/use-uncontrolled/index.js +12 -0
  31. package/build/index.d.ts +3 -0
  32. package/build/index.d.ts.map +1 -0
  33. package/build/index.js +2 -0
  34. package/build/utils/auto-contrast/index.d.ts +2 -0
  35. package/build/utils/auto-contrast/index.d.ts.map +1 -0
  36. package/build/utils/auto-contrast/index.js +50 -0
  37. package/build/utils/clamp/index.d.ts +2 -0
  38. package/build/utils/clamp/index.d.ts.map +1 -0
  39. package/build/utils/clamp/index.js +9 -0
  40. package/build/utils/context/index.d.ts +3 -0
  41. package/build/utils/context/index.d.ts.map +1 -0
  42. package/build/utils/context/index.js +2 -0
  43. package/build/utils/context/optional-context.d.ts +5 -0
  44. package/build/utils/context/optional-context.d.ts.map +1 -0
  45. package/build/utils/context/optional-context.js +10 -0
  46. package/build/utils/context/safe-context.d.ts +5 -0
  47. package/build/utils/context/safe-context.d.ts.map +1 -0
  48. package/build/utils/context/safe-context.js +14 -0
  49. package/build/utils/get-change-value/index.d.ts +10 -0
  50. package/build/utils/get-change-value/index.d.ts.map +1 -0
  51. package/build/utils/get-change-value/index.js +7 -0
  52. package/build/utils/index.d.ts +6 -0
  53. package/build/utils/index.d.ts.map +1 -0
  54. package/build/utils/index.js +5 -0
  55. package/build/utils/storage/index.d.ts +39 -0
  56. package/build/utils/storage/index.d.ts.map +1 -0
  57. package/build/utils/storage/index.js +150 -0
  58. package/build/utils/storage/storage.d.ts +1 -0
  59. package/build/utils/storage/storage.d.ts.map +1 -0
  60. package/build/utils/storage/storage.js +1 -0
  61. package/build/utils/storage/storage.test.d.ts +2 -0
  62. package/build/utils/storage/storage.test.d.ts.map +1 -0
  63. package/build/utils/storage/storage.test.js +153 -0
  64. package/package.json +29 -0
  65. package/refraktor-utils-0.0.1-alpha.0.tgz +0 -0
  66. package/src/hooks/index.ts +8 -0
  67. package/src/hooks/use-click-outside/index.ts +76 -0
  68. package/src/hooks/use-debounced-callback/index.ts +128 -0
  69. package/src/hooks/use-disclosure/index.ts +67 -0
  70. package/src/hooks/use-id/index.ts +6 -0
  71. package/src/hooks/use-isomorphic-layout-effect/index.ts +4 -0
  72. package/src/hooks/use-merged-refs/index.ts +45 -0
  73. package/src/hooks/use-resize-observer/index.ts +105 -0
  74. package/src/hooks/use-uncontrolled/index.ts +36 -0
  75. package/src/index.ts +2 -0
  76. package/src/utils/auto-contrast/index.ts +73 -0
  77. package/src/utils/clamp/index.ts +13 -0
  78. package/src/utils/context/index.ts +2 -0
  79. package/src/utils/context/optional-context.tsx +21 -0
  80. package/src/utils/context/safe-context.tsx +25 -0
  81. package/src/utils/get-change-value/index.ts +22 -0
  82. package/src/utils/index.ts +5 -0
  83. package/src/utils/storage/index.ts +203 -0
  84. package/tsconfig.json +13 -0
  85. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1 @@
1
+ $ tsc
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ChillWoW
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # @refraktor/utils
2
+
3
+ Utility and hooks library for Refraktor.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # NPM
9
+ npm install @refraktor/utils
10
+
11
+ # Bun
12
+ bun add @refraktor/utils
13
+ ```
14
+
15
+ ## Documentation
16
+
17
+ Coming Soon...
18
+
19
+ ## License
20
+
21
+ [MIT](LICENSE)
@@ -0,0 +1,9 @@
1
+ export { useId } from "./use-id";
2
+ export { useDisclosure } from "./use-disclosure";
3
+ export { useClickOutside } from "./use-click-outside";
4
+ export { useResizeObserver } from "./use-resize-observer";
5
+ export { useMergedRefs } from "./use-merged-refs";
6
+ export { useUncontrolled } from "./use-uncontrolled";
7
+ export { useDebouncedCallback } from "./use-debounced-callback";
8
+ export { useIsomorphicLayoutEffect } from "./use-isomorphic-layout-effect";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { useId } from "./use-id";
2
+ export { useDisclosure } from "./use-disclosure";
3
+ export { useClickOutside } from "./use-click-outside";
4
+ export { useResizeObserver } from "./use-resize-observer";
5
+ export { useMergedRefs } from "./use-merged-refs";
6
+ export { useUncontrolled } from "./use-uncontrolled";
7
+ export { useDebouncedCallback } from "./use-debounced-callback";
8
+ export { useIsomorphicLayoutEffect } from "./use-isomorphic-layout-effect";
@@ -0,0 +1,5 @@
1
+ export type UseClickOutsideEvent = keyof DocumentEventMap;
2
+ type UseClickOutsideNode = HTMLElement | null;
3
+ export declare function useClickOutside<T extends HTMLElement = HTMLElement>(handler: (event: Event) => void, events?: UseClickOutsideEvent[], nodes?: UseClickOutsideNode[]): import("react").RefObject<T | null>;
4
+ export {};
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-click-outside/index.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,GAAG,MAAM,gBAAgB,CAAC;AAE1D,KAAK,mBAAmB,GAAG,WAAW,GAAG,IAAI,CAAC;AAK9C,wBAAgB,eAAe,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC/D,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,EAC/B,MAAM,GAAE,oBAAoB,EAAmB,EAC/C,KAAK,GAAE,mBAAmB,EAAkB,uCA+D/C"}
@@ -0,0 +1,50 @@
1
+ import { useEffect, useRef } from "react";
2
+ const DEFAULT_EVENTS = ["mousedown", "touchstart"];
3
+ const DEFAULT_NODES = [];
4
+ export function useClickOutside(handler, events = DEFAULT_EVENTS, nodes = DEFAULT_NODES) {
5
+ const ref = useRef(null);
6
+ const handlerRef = useRef(handler);
7
+ useEffect(() => {
8
+ handlerRef.current = handler;
9
+ }, [handler]);
10
+ useEffect(() => {
11
+ const listener = (event) => {
12
+ const target = event.target;
13
+ if (!(target instanceof Node)) {
14
+ return;
15
+ }
16
+ const element = ref.current;
17
+ if (!element) {
18
+ return;
19
+ }
20
+ const path = typeof event.composedPath === "function"
21
+ ? event.composedPath()
22
+ : undefined;
23
+ const isInsideElement = path
24
+ ? path.includes(element)
25
+ : element.contains(target);
26
+ if (isInsideElement) {
27
+ return;
28
+ }
29
+ const isInsideAdditionalNode = nodes.some((node) => {
30
+ if (!node) {
31
+ return false;
32
+ }
33
+ return path ? path.includes(node) : node.contains(target);
34
+ });
35
+ if (isInsideAdditionalNode) {
36
+ return;
37
+ }
38
+ handlerRef.current(event);
39
+ };
40
+ for (const eventName of events) {
41
+ document.addEventListener(eventName, listener);
42
+ }
43
+ return () => {
44
+ for (const eventName of events) {
45
+ document.removeEventListener(eventName, listener);
46
+ }
47
+ };
48
+ }, [events, nodes]);
49
+ return ref;
50
+ }
@@ -0,0 +1,11 @@
1
+ export interface UseDebouncedCallbackOptions {
2
+ leading?: boolean;
3
+ trailing?: boolean;
4
+ }
5
+ export type UseDebouncedCallbackReturn<TArgs extends unknown[], TResult> = ((...args: TArgs) => void) & {
6
+ cancel: () => void;
7
+ flush: () => TResult | undefined;
8
+ isPending: () => boolean;
9
+ };
10
+ export declare function useDebouncedCallback<TArgs extends unknown[], TResult>(callback: (...args: TArgs) => TResult, delay: number, options?: UseDebouncedCallbackOptions): UseDebouncedCallbackReturn<TArgs, TResult>;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-debounced-callback/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,2BAA2B;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,0BAA0B,CAClC,KAAK,SAAS,OAAO,EAAE,EACvB,OAAO,IACP,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IACjC,SAAS,EAAE,MAAM,OAAO,CAAC;CAC5B,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,KAAK,SAAS,OAAO,EAAE,EAAE,OAAO,EACjE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,EACrC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,2BAAgC,GAC1C,0BAA0B,CAAC,KAAK,EAAE,OAAO,CAAC,CA2G5C"}
@@ -0,0 +1,88 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from "react";
2
+ export function useDebouncedCallback(callback, delay, options = {}) {
3
+ const { leading = false, trailing = true } = options;
4
+ const wait = Math.max(0, delay);
5
+ const callbackRef = useRef(callback);
6
+ const timeoutRef = useRef(null);
7
+ const lastArgsRef = useRef(null);
8
+ const shouldCallTrailingRef = useRef(false);
9
+ const resultRef = useRef(undefined);
10
+ useEffect(() => {
11
+ callbackRef.current = callback;
12
+ }, [callback]);
13
+ const invoke = useCallback((args) => {
14
+ const result = callbackRef.current(...args);
15
+ resultRef.current = result;
16
+ return result;
17
+ }, []);
18
+ const clearTimer = useCallback(() => {
19
+ if (timeoutRef.current !== null) {
20
+ clearTimeout(timeoutRef.current);
21
+ timeoutRef.current = null;
22
+ }
23
+ }, []);
24
+ const cancel = useCallback(() => {
25
+ clearTimer();
26
+ shouldCallTrailingRef.current = false;
27
+ lastArgsRef.current = null;
28
+ }, [clearTimer]);
29
+ const flush = useCallback(() => {
30
+ if (timeoutRef.current === null) {
31
+ return resultRef.current;
32
+ }
33
+ clearTimer();
34
+ if (trailing &&
35
+ shouldCallTrailingRef.current &&
36
+ lastArgsRef.current !== null) {
37
+ const next = invoke(lastArgsRef.current);
38
+ shouldCallTrailingRef.current = false;
39
+ lastArgsRef.current = null;
40
+ return next;
41
+ }
42
+ shouldCallTrailingRef.current = false;
43
+ lastArgsRef.current = null;
44
+ return resultRef.current;
45
+ }, [clearTimer, invoke, trailing]);
46
+ const isPending = useCallback(() => timeoutRef.current !== null, []);
47
+ const debounced = useMemo(() => {
48
+ const fn = (...args) => {
49
+ if (!leading && !trailing) {
50
+ return;
51
+ }
52
+ const hasTimer = timeoutRef.current !== null;
53
+ if (!hasTimer) {
54
+ if (leading) {
55
+ invoke(args);
56
+ shouldCallTrailingRef.current = false;
57
+ lastArgsRef.current = null;
58
+ }
59
+ else {
60
+ shouldCallTrailingRef.current = true;
61
+ lastArgsRef.current = args;
62
+ }
63
+ }
64
+ else if (trailing) {
65
+ shouldCallTrailingRef.current = true;
66
+ lastArgsRef.current = args;
67
+ }
68
+ clearTimer();
69
+ timeoutRef.current = setTimeout(() => {
70
+ timeoutRef.current = null;
71
+ if (trailing &&
72
+ shouldCallTrailingRef.current &&
73
+ lastArgsRef.current !== null) {
74
+ invoke(lastArgsRef.current);
75
+ }
76
+ shouldCallTrailingRef.current = false;
77
+ lastArgsRef.current = null;
78
+ }, wait);
79
+ };
80
+ return Object.assign(fn, {
81
+ cancel,
82
+ flush,
83
+ isPending
84
+ });
85
+ }, [cancel, clearTimer, flush, invoke, isPending, leading, trailing, wait]);
86
+ useEffect(() => cancel, [cancel]);
87
+ return debounced;
88
+ }
@@ -0,0 +1,12 @@
1
+ export interface UseDisclosureCallbacks {
2
+ onOpen?: () => void;
3
+ onClose?: () => void;
4
+ }
5
+ export interface UseDisclosureHandlers {
6
+ open: () => void;
7
+ close: () => void;
8
+ toggle: () => void;
9
+ }
10
+ export type UseDisclosureReturn = [boolean, UseDisclosureHandlers];
11
+ export declare function useDisclosure(initialState?: boolean, callbacks?: UseDisclosureCallbacks): UseDisclosureReturn;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-disclosure/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACnC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;AAEnE,wBAAgB,aAAa,CACzB,YAAY,UAAQ,EACpB,SAAS,CAAC,EAAE,sBAAsB,GACnC,mBAAmB,CAgDrB"}
@@ -0,0 +1,39 @@
1
+ import { useCallback, useMemo, useState } from "react";
2
+ export function useDisclosure(initialState = false, callbacks) {
3
+ const [opened, setOpened] = useState(initialState);
4
+ const { onOpen, onClose } = callbacks ?? {};
5
+ const open = useCallback(() => {
6
+ setOpened((isOpened) => {
7
+ if (!isOpened) {
8
+ onOpen?.();
9
+ }
10
+ return true;
11
+ });
12
+ }, [onOpen]);
13
+ const close = useCallback(() => {
14
+ setOpened((isOpened) => {
15
+ if (isOpened) {
16
+ onClose?.();
17
+ }
18
+ return false;
19
+ });
20
+ }, [onClose]);
21
+ const toggle = useCallback(() => {
22
+ setOpened((isOpened) => {
23
+ const next = !isOpened;
24
+ if (next) {
25
+ onOpen?.();
26
+ }
27
+ else {
28
+ onClose?.();
29
+ }
30
+ return next;
31
+ });
32
+ }, [onOpen, onClose]);
33
+ const handlers = useMemo(() => ({
34
+ open,
35
+ close,
36
+ toggle
37
+ }), [open, close, toggle]);
38
+ return [opened, handlers];
39
+ }
@@ -0,0 +1,2 @@
1
+ export declare function useId(propId?: any): string;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-id/index.ts"],"names":[],"mappings":"AAEA,wBAAgB,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,GAAG,MAAM,CAG1C"}
@@ -0,0 +1,5 @@
1
+ import { useId as useReactId } from "react";
2
+ export function useId(propId) {
3
+ const id = useReactId();
4
+ return propId ?? id;
5
+ }
@@ -0,0 +1,3 @@
1
+ import { useLayoutEffect } from "react";
2
+ export declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-isomorphic-layout-effect/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,eAAe,EAAE,MAAM,OAAO,CAAC;AAEnD,eAAO,MAAM,yBAAyB,EAAE,OAAO,eACgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { useEffect, useLayoutEffect } from "react";
2
+ export const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
@@ -0,0 +1,6 @@
1
+ import { Ref, RefCallback } from "react";
2
+ type AnyRef<T> = Ref<T> | undefined;
3
+ export declare function mergeRefs<T>(...refs: AnyRef<T>[]): RefCallback<T>;
4
+ export declare function useMergedRefs<T>(...refs: AnyRef<T>[]): RefCallback<T>;
5
+ export {};
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-merged-refs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAe,WAAW,EAAE,MAAM,OAAO,CAAC;AAEtD,KAAK,MAAM,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;AAepC,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAuBjE;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,kBAEpD"}
@@ -0,0 +1,38 @@
1
+ import { useCallback } from "react";
2
+ function applyRef(ref, value) {
3
+ if (!ref)
4
+ return;
5
+ if (typeof ref === "function") {
6
+ return ref(value);
7
+ }
8
+ if (typeof ref === "object" && "current" in ref) {
9
+ ref.current = value;
10
+ }
11
+ }
12
+ export function mergeRefs(...refs) {
13
+ const cleanups = new Map();
14
+ return (node) => {
15
+ for (const ref of refs) {
16
+ const cleanup = applyRef(ref, node);
17
+ if (cleanup)
18
+ cleanups.set(ref, cleanup);
19
+ }
20
+ if (cleanups.size > 0) {
21
+ return () => {
22
+ for (const ref of refs) {
23
+ const fn = cleanups.get(ref);
24
+ if (typeof fn === "function") {
25
+ fn();
26
+ }
27
+ else {
28
+ applyRef(ref, null);
29
+ }
30
+ }
31
+ cleanups.clear();
32
+ };
33
+ }
34
+ };
35
+ }
36
+ export function useMergedRefs(...refs) {
37
+ return useCallback(mergeRefs(...refs), refs);
38
+ }
@@ -0,0 +1,15 @@
1
+ export interface UseResizeObserverSize {
2
+ width: number;
3
+ height: number;
4
+ }
5
+ export interface UseResizeObserverOptions {
6
+ initialSize?: UseResizeObserverSize;
7
+ box?: ResizeObserverBoxOptions;
8
+ onResize?: (entry: ResizeObserverEntry) => void;
9
+ }
10
+ export interface UseResizeObserverReturn<T extends HTMLElement = HTMLElement> extends UseResizeObserverSize {
11
+ ref: (node: T | null) => void;
12
+ entry: ResizeObserverEntry | null;
13
+ }
14
+ export declare function useResizeObserver<T extends HTMLElement = HTMLElement>(options?: UseResizeObserverOptions): UseResizeObserverReturn<T>;
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-resize-observer/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,wBAAwB;IACrC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,GAAG,CAAC,EAAE,wBAAwB,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,CACxE,SAAQ,qBAAqB;IAC7B,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9B,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACrC;AAWD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EACjE,OAAO,GAAE,wBAA6B,GACvC,uBAAuB,CAAC,CAAC,CAAC,CA0E5B"}
@@ -0,0 +1,65 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ const DEFAULT_SIZE = {
3
+ width: 0,
4
+ height: 0
5
+ };
6
+ export function useResizeObserver(options = {}) {
7
+ const { initialSize = DEFAULT_SIZE, box, onResize } = options;
8
+ const [node, setNode] = useState(null);
9
+ const [state, setState] = useState(() => ({
10
+ width: initialSize.width,
11
+ height: initialSize.height,
12
+ entry: null
13
+ }));
14
+ const onResizeRef = useRef(onResize);
15
+ useEffect(() => {
16
+ onResizeRef.current = onResize;
17
+ }, [onResize]);
18
+ const ref = useCallback((nextNode) => {
19
+ setNode(nextNode);
20
+ }, []);
21
+ useEffect(() => {
22
+ if (!node) {
23
+ return;
24
+ }
25
+ if (typeof window === "undefined" ||
26
+ typeof ResizeObserver === "undefined") {
27
+ return;
28
+ }
29
+ const observer = new ResizeObserver(([entry]) => {
30
+ if (!entry) {
31
+ return;
32
+ }
33
+ const nextWidth = entry.contentRect.width;
34
+ const nextHeight = entry.contentRect.height;
35
+ setState((current) => {
36
+ if (current.width === nextWidth &&
37
+ current.height === nextHeight &&
38
+ current.entry !== null) {
39
+ return current;
40
+ }
41
+ return {
42
+ width: nextWidth,
43
+ height: nextHeight,
44
+ entry
45
+ };
46
+ });
47
+ onResizeRef.current?.(entry);
48
+ });
49
+ try {
50
+ observer.observe(node, box ? { box } : undefined);
51
+ }
52
+ catch {
53
+ observer.observe(node);
54
+ }
55
+ return () => {
56
+ observer.disconnect();
57
+ };
58
+ }, [box, node]);
59
+ return {
60
+ ref,
61
+ width: state.width,
62
+ height: state.height,
63
+ entry: state.entry
64
+ };
65
+ }
@@ -0,0 +1,13 @@
1
+ export type UseUncontrolledProps<T> = {
2
+ value?: T;
3
+ defaultValue?: T;
4
+ finalValue?: T;
5
+ onChange?: (value: T, ...payload: any[]) => void;
6
+ };
7
+ export type UseUncontrolledReturn<T> = [
8
+ T,
9
+ (value: T, ...payload: any[]) => void,
10
+ boolean
11
+ ];
12
+ export declare function useUncontrolled<T>({ value, defaultValue, finalValue, onChange }: UseUncontrolledProps<T>): UseUncontrolledReturn<T>;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-uncontrolled/index.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAAI;IAClC,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,YAAY,CAAC,EAAE,CAAC,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;CACpD,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,CAAC,IAAI;IACnC,CAAC;IACD,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,KAAK,IAAI;IACrC,OAAO;CACV,CAAC;AAEF,wBAAgB,eAAe,CAAC,CAAC,EAAE,EAC/B,KAAK,EACL,YAAY,EACZ,UAAU,EACV,QAAmB,EACtB,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAepD"}
@@ -0,0 +1,12 @@
1
+ import { useState } from "react";
2
+ export function useUncontrolled({ value, defaultValue, finalValue, onChange = () => { } }) {
3
+ const [state, setState] = useState(defaultValue !== undefined ? defaultValue : finalValue);
4
+ const handleChange = (val, ...payload) => {
5
+ setState(val);
6
+ onChange?.(val, ...payload);
7
+ };
8
+ if (value !== undefined) {
9
+ return [value, onChange, true];
10
+ }
11
+ return [state, handleChange, false];
12
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./hooks";
2
+ export * from "./utils";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
package/build/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./hooks";
2
+ export * from "./utils";
@@ -0,0 +1,2 @@
1
+ export declare function getAutoContrastTextColor(background: string, darkText: string, lightText: string, fallbackColor: string): string;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/auto-contrast/index.ts"],"names":[],"mappings":"AAsDA,wBAAgB,wBAAwB,CACpC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACtB,MAAM,CAaR"}
@@ -0,0 +1,50 @@
1
+ function parseHexColor(color) {
2
+ const value = color.trim().replace(/^#/, "");
3
+ if (![3, 4, 6, 8].includes(value.length))
4
+ return null;
5
+ if (!/^[0-9a-fA-F]+$/.test(value))
6
+ return null;
7
+ const normalized = value.length === 3 || value.length === 4
8
+ ? value
9
+ .slice(0, 3)
10
+ .split("")
11
+ .map((char) => `${char}${char}`)
12
+ .join("")
13
+ : value.slice(0, 6);
14
+ return {
15
+ r: Number.parseInt(normalized.slice(0, 2), 16),
16
+ g: Number.parseInt(normalized.slice(2, 4), 16),
17
+ b: Number.parseInt(normalized.slice(4, 6), 16)
18
+ };
19
+ }
20
+ function toRelativeLuminance(channel) {
21
+ const sRGB = channel / 255;
22
+ if (sRGB <= 0.03928)
23
+ return sRGB / 12.92;
24
+ return ((sRGB + 0.055) / 1.055) ** 2.4;
25
+ }
26
+ function getLuminance(color) {
27
+ return (0.2126 * toRelativeLuminance(color.r) +
28
+ 0.7152 * toRelativeLuminance(color.g) +
29
+ 0.0722 * toRelativeLuminance(color.b));
30
+ }
31
+ function getContrastRatio(background, foreground) {
32
+ const backgroundLuminance = getLuminance(background);
33
+ const foregroundLuminance = getLuminance(foreground);
34
+ const lighter = Math.max(backgroundLuminance, foregroundLuminance);
35
+ const darker = Math.min(backgroundLuminance, foregroundLuminance);
36
+ return (lighter + 0.05) / (darker + 0.05);
37
+ }
38
+ export function getAutoContrastTextColor(background, darkText, lightText, fallbackColor) {
39
+ const backgroundRGB = parseHexColor(background);
40
+ if (!backgroundRGB)
41
+ return fallbackColor;
42
+ const darkTextRGB = parseHexColor(darkText);
43
+ const lightTextRGB = parseHexColor(lightText);
44
+ if (!darkTextRGB || !lightTextRGB)
45
+ return fallbackColor;
46
+ return getContrastRatio(backgroundRGB, darkTextRGB) >=
47
+ getContrastRatio(backgroundRGB, lightTextRGB)
48
+ ? darkText
49
+ : lightText;
50
+ }
@@ -0,0 +1,2 @@
1
+ export declare function clamp(value: number, min: number | undefined, max: number | undefined): number;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/clamp/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CACjB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,CAQR"}
@@ -0,0 +1,9 @@
1
+ export function clamp(value, min, max) {
2
+ if (min === undefined && max === undefined)
3
+ return value;
4
+ if (min !== undefined && max === undefined)
5
+ return Math.max(min, value);
6
+ if (min === undefined && max !== undefined)
7
+ return Math.min(max, value);
8
+ return Math.min(Math.max(value, min), max);
9
+ }
@@ -0,0 +1,3 @@
1
+ export { createOptionalContext } from "./optional-context";
2
+ export { createSafeContext } from "./safe-context";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/context/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createOptionalContext } from "./optional-context";
2
+ export { createSafeContext } from "./safe-context";
@@ -0,0 +1,5 @@
1
+ export declare function createOptionalContext<ContextValue>(initialValue?: ContextValue | null): readonly [({ value, children }: {
2
+ value: ContextValue;
3
+ children: React.ReactNode;
4
+ }) => import("react/jsx-runtime").JSX.Element, () => ContextValue | null];
5
+ //# sourceMappingURL=optional-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optional-context.d.ts","sourceRoot":"","sources":["../../../src/utils/context/optional-context.tsx"],"names":[],"mappings":"AAEA,wBAAgB,qBAAqB,CAAC,YAAY,EAC9C,YAAY,GAAE,YAAY,GAAG,IAAW,mCASrC;IACC,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC7B,yEAKJ"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from "react";
3
+ export function createOptionalContext(initialValue = null) {
4
+ const Context = createContext(initialValue);
5
+ const useOptionalContext = () => useContext(Context);
6
+ const Provider = ({ value, children }) => {
7
+ return _jsx(Context.Provider, { value: value, children: children });
8
+ };
9
+ return [Provider, useOptionalContext];
10
+ }
@@ -0,0 +1,5 @@
1
+ export declare function createSafeContext<ContextValue>(err: string): readonly [({ children, value }: {
2
+ children: React.ReactNode;
3
+ value: ContextValue;
4
+ }) => import("react/jsx-runtime").JSX.Element, () => ContextValue & ({} | undefined)];
5
+ //# sourceMappingURL=safe-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-context.d.ts","sourceRoot":"","sources":["../../../src/utils/context/safe-context.tsx"],"names":[],"mappings":"AAEA,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,GAAG,EAAE,MAAM,mCAgBpD;IACC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,EAAE,YAAY,CAAC;CACvB,qFAGJ"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from "react";
3
+ export function createSafeContext(err) {
4
+ const Context = createContext(null);
5
+ const useSafeContext = () => {
6
+ const context = useContext(Context);
7
+ if (context === null) {
8
+ throw new Error(err);
9
+ }
10
+ return context;
11
+ };
12
+ const Provider = ({ children, value }) => _jsx(Context.Provider, { value: value, children: children });
13
+ return [Provider, useSafeContext];
14
+ }