@journ/lift 0.1.1 → 0.2.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 (76) hide show
  1. package/README.md +39 -9
  2. package/dist/env-C0PNnbwt.js +4 -0
  3. package/dist/logger-Dse1660l.js +33 -0
  4. package/dist/prefers-reduced-motion.d.ts +3 -2
  5. package/dist/prefers-reduced-motion.js +1 -3
  6. package/dist/required-context.d.ts +3 -2
  7. package/dist/required-context.js +2 -2
  8. package/dist/try-catch-D4d3N9_W.js +29 -0
  9. package/dist/types-p0KNRcj3.d.ts +4 -0
  10. package/dist/use-battery.d.ts +12 -0
  11. package/dist/use-battery.js +64 -0
  12. package/dist/use-browser.d.ts +6 -0
  13. package/dist/use-browser.js +51 -0
  14. package/dist/use-callback-ref.d.ts +5 -0
  15. package/dist/use-callback-ref.js +11 -0
  16. package/dist/use-controllable-state.d.ts +3 -2
  17. package/dist/use-controllable-state.js +6 -4
  18. package/dist/use-debounce-state.d.ts +9 -0
  19. package/dist/use-debounce-state.js +28 -0
  20. package/dist/use-debounced-callback.d.ts +16 -0
  21. package/dist/use-debounced-callback.js +68 -0
  22. package/dist/use-debounced-value.d.ts +3 -2
  23. package/dist/use-debounced-value.js +3 -3
  24. package/dist/use-did-update.d.ts +5 -0
  25. package/dist/use-did-update.js +24 -0
  26. package/dist/use-disclosure.d.ts +15 -0
  27. package/dist/use-disclosure.js +16 -0
  28. package/dist/use-draft.d.ts +7 -6
  29. package/dist/use-draft.js +2 -2
  30. package/dist/use-haptic.d.ts +8 -0
  31. package/dist/use-haptic.js +84 -0
  32. package/dist/use-headroom.d.ts +18 -0
  33. package/dist/use-headroom.js +65 -0
  34. package/dist/use-idle-queue.d.ts +28 -0
  35. package/dist/use-idle-queue.js +221 -0
  36. package/dist/use-intersection-observer.d.ts +17 -0
  37. package/dist/use-intersection-observer.js +50 -0
  38. package/dist/use-isomorphic-effect.d.ts +5 -0
  39. package/dist/use-isomorphic-effect.js +5 -0
  40. package/dist/use-keybindings.d.ts +14 -0
  41. package/dist/use-keybindings.js +76 -0
  42. package/dist/use-local-storage.d.ts +13 -0
  43. package/dist/use-local-storage.js +76 -0
  44. package/dist/use-logger.d.ts +4 -0
  45. package/dist/use-logger.js +17 -0
  46. package/dist/use-long-press.d.ts +12 -0
  47. package/dist/use-long-press.js +43 -0
  48. package/dist/use-map.d.ts +4 -0
  49. package/dist/use-map.js +30 -0
  50. package/dist/use-measure.d.ts +8 -0
  51. package/dist/use-measure.js +27 -0
  52. package/dist/use-media-query.d.ts +14 -0
  53. package/dist/use-media-query.js +24 -0
  54. package/dist/use-mouse.d.ts +18 -0
  55. package/dist/use-mouse.js +40 -0
  56. package/dist/use-network.d.ts +17 -0
  57. package/dist/use-network.js +38 -0
  58. package/dist/use-page-leave.d.ts +4 -0
  59. package/dist/use-page-leave.js +11 -0
  60. package/dist/use-pagination.d.ts +19 -0
  61. package/dist/use-pagination.js +55 -0
  62. package/dist/use-reduced-motion.d.ts +4 -0
  63. package/dist/use-reduced-motion.js +5 -0
  64. package/dist/use-scroll-direction.d.ts +5 -0
  65. package/dist/use-scroll-direction.js +33 -0
  66. package/dist/use-uncontrolled.d.ts +11 -0
  67. package/dist/use-uncontrolled.js +21 -0
  68. package/dist/use-validated-state.d.ts +10 -0
  69. package/dist/use-validated-state.js +22 -0
  70. package/dist/use-window-event.d.ts +5 -0
  71. package/dist/use-window-event.js +11 -0
  72. package/dist/use-window-scroll.d.ts +10 -0
  73. package/dist/use-window-scroll.js +33 -0
  74. package/package.json +149 -9
  75. package/dist/index.d.ts +0 -6
  76. package/dist/index.js +0 -6
@@ -0,0 +1,76 @@
1
+ import { n as tryCatchSync } from "./try-catch-D4d3N9_W.js";
2
+ import { t as logger } from "./logger-Dse1660l.js";
3
+ import { useCallback, useMemo, useSyncExternalStore } from "react";
4
+ //#region src/use-local-storage.ts
5
+ const serializeJSON = (value, hookName) => {
6
+ const result = tryCatchSync(() => JSON.stringify(value));
7
+ if (!result.success) throw new Error(`${hookName}: Failed to serialize the value`);
8
+ return result.data;
9
+ };
10
+ const deserializeJSON = (value) => {
11
+ const result = tryCatchSync(() => JSON.parse(value));
12
+ return result.success ? result.data : value;
13
+ };
14
+ const createStorageHandler = (type, hookName) => {
15
+ const attempt = (fn, failure, fallback) => {
16
+ const result = tryCatchSync(fn);
17
+ if (result.success) return result.data;
18
+ logger.warn(`${hookName}: ${failure}`);
19
+ return fallback;
20
+ };
21
+ const getItem = (key) => attempt(() => window[type].getItem(key), "Failed to get value from storage", null);
22
+ const setItem = (key, value) => attempt(() => window[type].setItem(key, value), "Failed to set value to storage", void 0);
23
+ const removeItem = (key) => attempt(() => window[type].removeItem(key), "Failed to remove value from storage", void 0);
24
+ return {
25
+ getItem,
26
+ setItem,
27
+ removeItem
28
+ };
29
+ };
30
+ const getServerSnapshot = () => null;
31
+ const createUseStorage = (type, hookName) => {
32
+ const eventName = type === "localStorage" ? "local-storage" : "session-storage";
33
+ const { getItem, setItem, removeItem } = createStorageHandler(type, hookName);
34
+ const subscribe = (callback) => {
35
+ window.addEventListener("storage", callback);
36
+ window.addEventListener(eventName, callback);
37
+ return () => {
38
+ window.removeEventListener("storage", callback);
39
+ window.removeEventListener(eventName, callback);
40
+ };
41
+ };
42
+ const defaultSerialize = (value) => serializeJSON(value, hookName);
43
+ const notify = () => window.dispatchEvent(new Event(eventName));
44
+ return ({ key, defaultValue, deserialize = deserializeJSON, serialize = defaultSerialize }) => {
45
+ const getSnapshot = useCallback(() => getItem(key), [key]);
46
+ const raw = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
47
+ const stored = useMemo(() => raw === null ? void 0 : deserialize(raw), [raw, deserialize]);
48
+ const setStorageValue = useCallback((val) => {
49
+ let next;
50
+ if (val instanceof Function) {
51
+ const current = getItem(key);
52
+ next = val(current === null ? defaultValue : deserialize(current));
53
+ } else next = val;
54
+ setItem(key, serialize(next));
55
+ notify();
56
+ }, [
57
+ key,
58
+ defaultValue,
59
+ deserialize,
60
+ serialize
61
+ ]);
62
+ const removeStorageValue = useCallback(() => {
63
+ removeItem(key);
64
+ notify();
65
+ }, [key]);
66
+ return [
67
+ raw === null ? defaultValue : stored,
68
+ setStorageValue,
69
+ removeStorageValue
70
+ ];
71
+ };
72
+ };
73
+ const useLocalStorage = createUseStorage("localStorage", "use-local-storage");
74
+ const useSessionStorage = createUseStorage("sessionStorage", "use-session-storage");
75
+ //#endregion
76
+ export { useLocalStorage, useSessionStorage };
@@ -0,0 +1,4 @@
1
+ //#region src/use-logger.d.ts
2
+ declare const useLogger: (componentName: string, props: unknown[]) => void;
3
+ //#endregion
4
+ export { useLogger };
@@ -0,0 +1,17 @@
1
+ import { useDidUpdate } from "./use-did-update.js";
2
+ import { t as logger } from "./logger-Dse1660l.js";
3
+ import { useEffect, useEffectEvent } from "react";
4
+ //#region src/use-logger.ts
5
+ const useLogger = (componentName, props) => {
6
+ const logMount = useEffectEvent(() => logger.log(`${componentName} mounted`, ...props));
7
+ const logUnmount = useEffectEvent(() => logger.log(`${componentName} unmounted`));
8
+ useEffect(() => {
9
+ logMount();
10
+ return () => logUnmount();
11
+ }, []);
12
+ useDidUpdate(() => {
13
+ logger.log(`${componentName} updated`, ...props);
14
+ }, props);
15
+ };
16
+ //#endregion
17
+ export { useLogger };
@@ -0,0 +1,12 @@
1
+ import { PointerEvent, SyntheticEvent } from "react";
2
+ //#region src/use-long-press.d.ts
3
+ type LongPressHandlers = {
4
+ readonly onPointerDown: (event: PointerEvent) => void;
5
+ readonly onPointerMove: (event: PointerEvent) => void;
6
+ readonly onPointerUp: () => void;
7
+ readonly onPointerCancel: () => void;
8
+ readonly onContextMenu: (event: SyntheticEvent) => void;
9
+ };
10
+ declare const useLongPress: (onLongPress: () => void, disabled?: boolean) => LongPressHandlers;
11
+ //#endregion
12
+ export { useLongPress };
@@ -0,0 +1,43 @@
1
+ import { useCallback, useEffect, useRef } from "react";
2
+ //#region src/use-long-press.ts
3
+ const HOLD_MS = 500;
4
+ const SLOP_PX = 10;
5
+ const useLongPress = (onLongPress, disabled = false) => {
6
+ const timer = useRef(null);
7
+ const origin = useRef(null);
8
+ const cancel = useCallback(() => {
9
+ if (timer.current !== null) {
10
+ clearTimeout(timer.current);
11
+ timer.current = null;
12
+ }
13
+ origin.current = null;
14
+ }, []);
15
+ useEffect(() => cancel, [cancel]);
16
+ return {
17
+ onPointerDown: useCallback((event) => {
18
+ if (disabled) return;
19
+ cancel();
20
+ origin.current = {
21
+ x: event.clientX,
22
+ y: event.clientY
23
+ };
24
+ timer.current = setTimeout(() => {
25
+ timer.current = null;
26
+ onLongPress();
27
+ }, HOLD_MS);
28
+ }, [
29
+ disabled,
30
+ onLongPress,
31
+ cancel
32
+ ]),
33
+ onPointerMove: useCallback((event) => {
34
+ if (!origin.current) return;
35
+ if (Math.abs(event.clientX - origin.current.x) > SLOP_PX || Math.abs(event.clientY - origin.current.y) > SLOP_PX) cancel();
36
+ }, [cancel]),
37
+ onPointerUp: cancel,
38
+ onPointerCancel: cancel,
39
+ onContextMenu: useCallback((event) => event.preventDefault(), [])
40
+ };
41
+ };
42
+ //#endregion
43
+ export { useLongPress };
@@ -0,0 +1,4 @@
1
+ //#region src/use-map.d.ts
2
+ declare const useMap: <K, V>(initialState?: [K, V][]) => Map<K, V>;
3
+ //#endregion
4
+ export { useMap };
@@ -0,0 +1,30 @@
1
+ import { useMemo, useRef, useState } from "react";
2
+ //#region src/use-map.ts
3
+ const useMap = (initialState) => {
4
+ const [map, setMap] = useState(() => new Map(initialState));
5
+ const latest = useRef(map);
6
+ return useMemo(() => {
7
+ const view = new Map(map);
8
+ const commit = (next) => {
9
+ latest.current = next;
10
+ setMap(next);
11
+ };
12
+ view.set = (key, value) => {
13
+ commit(new Map(latest.current).set(key, value));
14
+ return view;
15
+ };
16
+ view.delete = (key) => {
17
+ const existed = latest.current.has(key);
18
+ if (existed) {
19
+ const next = new Map(latest.current);
20
+ next.delete(key);
21
+ commit(next);
22
+ }
23
+ return existed;
24
+ };
25
+ view.clear = () => commit(/* @__PURE__ */ new Map());
26
+ return view;
27
+ }, [map]);
28
+ };
29
+ //#endregion
30
+ export { useMap };
@@ -0,0 +1,8 @@
1
+ //#region src/use-measure.d.ts
2
+ type Dimensions = {
3
+ width: number | null;
4
+ height: number | null;
5
+ };
6
+ declare const useMeasure: () => [(node: Element | null) => void, Dimensions];
7
+ //#endregion
8
+ export { useMeasure };
@@ -0,0 +1,27 @@
1
+ import { useCallback, useRef, useState } from "react";
2
+ //#region src/use-measure.ts
3
+ const EMPTY = {
4
+ width: null,
5
+ height: null
6
+ };
7
+ const useMeasure = () => {
8
+ const [dimensions, setDimensions] = useState(EMPTY);
9
+ const observerRef = useRef(null);
10
+ return [useCallback((node) => {
11
+ observerRef.current?.disconnect();
12
+ observerRef.current = null;
13
+ if (node?.nodeType !== Node.ELEMENT_NODE) return;
14
+ const observer = new ResizeObserver(([entry]) => {
15
+ if (!entry?.borderBoxSize) return;
16
+ const box = entry.borderBoxSize[0];
17
+ setDimensions(box ? {
18
+ width: box.inlineSize,
19
+ height: box.blockSize
20
+ } : EMPTY);
21
+ });
22
+ observer.observe(node);
23
+ observerRef.current = observer;
24
+ }, []), dimensions];
25
+ };
26
+ //#endregion
27
+ export { useMeasure };
@@ -0,0 +1,14 @@
1
+ //#region src/use-media-query.d.ts
2
+ declare const breakpoints: {
3
+ readonly sm: "(min-width: 40rem)";
4
+ readonly md: "(min-width: 48rem)";
5
+ readonly "max-md": "(width < 48rem)";
6
+ readonly lg: "(min-width: 64rem)";
7
+ readonly "max-lg": "(width < 64rem)";
8
+ };
9
+ type Breakpoint = keyof typeof breakpoints;
10
+ type BreakpointValue = (typeof breakpoints)[Breakpoint];
11
+ declare const useMediaQuery: (query: BreakpointValue | string) => boolean;
12
+ declare const useBreakpoint: (breakpoint: Breakpoint) => boolean;
13
+ //#endregion
14
+ export { type Breakpoint, breakpoints, useBreakpoint, useMediaQuery };
@@ -0,0 +1,24 @@
1
+ import { useCallback, useSyncExternalStore } from "react";
2
+ //#region src/use-media-query.ts
3
+ const breakpoints = {
4
+ sm: "(min-width: 40rem)",
5
+ md: "(min-width: 48rem)",
6
+ "max-md": "(width < 48rem)",
7
+ lg: "(min-width: 64rem)",
8
+ "max-lg": "(width < 64rem)"
9
+ };
10
+ const getServerSnapshot = () => {
11
+ throw new Error("useMediaQuery is a client-only hook");
12
+ };
13
+ const useMediaQuery = (query) => {
14
+ const subscribe = useCallback((callback) => {
15
+ const mediaQueryList = window.matchMedia(query);
16
+ mediaQueryList.addEventListener("change", callback);
17
+ return () => mediaQueryList.removeEventListener("change", callback);
18
+ }, [query]);
19
+ const getSnapshot = useCallback(() => window.matchMedia(query).matches, [query]);
20
+ return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
21
+ };
22
+ const useBreakpoint = (breakpoint) => useMediaQuery(breakpoints[breakpoint]);
23
+ //#endregion
24
+ export { breakpoints, useBreakpoint, useMediaQuery };
@@ -0,0 +1,18 @@
1
+ import { RefCallback } from "react";
2
+ //#region src/use-mouse.d.ts
3
+ type UseMouseOptions = {
4
+ resetOnExit?: boolean;
5
+ };
6
+ type UseMouseReturnValue<T extends HTMLElement = HTMLElement> = {
7
+ ref: RefCallback<T>;
8
+ x: number;
9
+ y: number;
10
+ };
11
+ type UseMousePositionReturnValue = {
12
+ x: number;
13
+ y: number;
14
+ };
15
+ declare const useMouse: <T extends HTMLElement = HTMLElement>({ resetOnExit }?: UseMouseOptions) => UseMouseReturnValue<T>;
16
+ declare const useMousePosition: () => UseMousePositionReturnValue;
17
+ //#endregion
18
+ export { type UseMouseOptions, type UseMousePositionReturnValue, type UseMouseReturnValue, useMouse, useMousePosition };
@@ -0,0 +1,40 @@
1
+ import { useWindowEvent } from "./use-window-event.js";
2
+ import { useCallback, useState } from "react";
3
+ //#region src/use-mouse.ts
4
+ const ORIGIN = {
5
+ x: 0,
6
+ y: 0
7
+ };
8
+ const useMouse = ({ resetOnExit = false } = {}) => {
9
+ const [position, setPosition] = useState(ORIGIN);
10
+ return {
11
+ ref: useCallback((node) => {
12
+ if (!node) return;
13
+ const trackPosition = (event) => {
14
+ const rect = node.getBoundingClientRect();
15
+ setPosition({
16
+ x: Math.max(0, Math.round(event.clientX - rect.left)),
17
+ y: Math.max(0, Math.round(event.clientY - rect.top))
18
+ });
19
+ };
20
+ const resetPosition = () => setPosition(ORIGIN);
21
+ node.addEventListener("mousemove", trackPosition);
22
+ if (resetOnExit) node.addEventListener("mouseleave", resetPosition);
23
+ return () => {
24
+ node.removeEventListener("mousemove", trackPosition);
25
+ node.removeEventListener("mouseleave", resetPosition);
26
+ };
27
+ }, [resetOnExit]),
28
+ ...position
29
+ };
30
+ };
31
+ const useMousePosition = () => {
32
+ const [position, setPosition] = useState(ORIGIN);
33
+ useWindowEvent("mousemove", (event) => setPosition({
34
+ x: event.clientX,
35
+ y: event.clientY
36
+ }));
37
+ return position;
38
+ };
39
+ //#endregion
40
+ export { useMouse, useMousePosition };
@@ -0,0 +1,17 @@
1
+ //#region src/use-network.d.ts
2
+ type EffectiveType = "slow-2g" | "2g" | "3g" | "4g";
3
+ type ConnectionType = "bluetooth" | "cellular" | "ethernet" | "wifi" | "wimax" | "none" | "other" | "unknown";
4
+ type NetworkStatus = {
5
+ downlink?: number;
6
+ downlinkMax?: number;
7
+ effectiveType?: EffectiveType;
8
+ rtt?: number;
9
+ saveData?: boolean;
10
+ type?: ConnectionType;
11
+ };
12
+ type NetworkState = NetworkStatus & {
13
+ online: boolean;
14
+ };
15
+ declare const useNetwork: () => NetworkState;
16
+ //#endregion
17
+ export { useNetwork };
@@ -0,0 +1,38 @@
1
+ import { useMemo, useSyncExternalStore } from "react";
2
+ //#region src/use-network.ts
3
+ const getConnection = () => {
4
+ if (typeof navigator === "undefined") return;
5
+ const nav = navigator;
6
+ return nav.connection ?? nav.mozConnection ?? nav.webkitConnection;
7
+ };
8
+ const readNetworkState = () => {
9
+ const connection = getConnection();
10
+ return {
11
+ online: typeof navigator !== "undefined" ? navigator.onLine : true,
12
+ downlink: connection?.downlink,
13
+ downlinkMax: connection?.downlinkMax,
14
+ effectiveType: connection?.effectiveType,
15
+ rtt: connection?.rtt,
16
+ saveData: connection?.saveData,
17
+ type: connection?.type
18
+ };
19
+ };
20
+ const subscribe = (callback) => {
21
+ const connection = getConnection();
22
+ window.addEventListener("online", callback);
23
+ window.addEventListener("offline", callback);
24
+ connection?.addEventListener("change", callback);
25
+ return () => {
26
+ window.removeEventListener("online", callback);
27
+ window.removeEventListener("offline", callback);
28
+ connection?.removeEventListener("change", callback);
29
+ };
30
+ };
31
+ const getSnapshot = () => JSON.stringify(readNetworkState());
32
+ const getServerSnapshot = () => JSON.stringify({ online: true });
33
+ const useNetwork = () => {
34
+ const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
35
+ return useMemo(() => JSON.parse(snapshot), [snapshot]);
36
+ };
37
+ //#endregion
38
+ export { useNetwork };
@@ -0,0 +1,4 @@
1
+ //#region src/use-page-leave.d.ts
2
+ declare const usePageLeave: (onPageLeave: () => void) => void;
3
+ //#endregion
4
+ export { usePageLeave };
@@ -0,0 +1,11 @@
1
+ import { useEffect, useEffectEvent } from "react";
2
+ //#region src/use-page-leave.ts
3
+ const usePageLeave = (onPageLeave) => {
4
+ const onPageLeaveEvent = useEffectEvent(onPageLeave);
5
+ useEffect(() => {
6
+ document.documentElement.addEventListener("mouseleave", onPageLeaveEvent);
7
+ return () => document.documentElement.removeEventListener("mouseleave", onPageLeaveEvent);
8
+ }, []);
9
+ };
10
+ //#endregion
11
+ export { usePageLeave };
@@ -0,0 +1,19 @@
1
+ //#region src/use-pagination.d.ts
2
+ declare const DOTS: "...";
3
+ type PaginationItem = number | typeof DOTS;
4
+ type UsePaginationOptions = {
5
+ initialPage?: number;
6
+ page?: number;
7
+ total: number;
8
+ siblings?: number;
9
+ boundaries?: number;
10
+ onChange?: (page: number) => void;
11
+ };
12
+ type UsePaginationReturnValue = {
13
+ range: PaginationItem[];
14
+ active: number;
15
+ setPage: (page: number) => void;
16
+ };
17
+ declare const usePagination: ({ total, siblings, boundaries, page, initialPage, onChange }: UsePaginationOptions) => UsePaginationReturnValue;
18
+ //#endregion
19
+ export { DOTS, usePagination };
@@ -0,0 +1,55 @@
1
+ import { useUncontrolled } from "./use-uncontrolled.js";
2
+ import { useMemo } from "react";
3
+ //#region src/use-pagination.ts
4
+ const DOTS = "...";
5
+ const range = (start, end) => Array.from({ length: end - start + 1 }, (_, index) => index + start);
6
+ const usePagination = ({ total, siblings = 1, boundaries = 1, page, initialPage = 1, onChange }) => {
7
+ const totalPages = Math.max(Math.trunc(total), 0);
8
+ const [activePage, setPage] = useUncontrolled({
9
+ value: page,
10
+ defaultValue: initialPage,
11
+ finalValue: initialPage,
12
+ onChange
13
+ });
14
+ return {
15
+ range: useMemo(() => {
16
+ if (siblings * 2 + 3 + boundaries * 2 >= totalPages) return range(1, totalPages);
17
+ const leftSiblingIndex = Math.max(activePage - siblings, boundaries);
18
+ const rightSiblingIndex = Math.min(activePage + siblings, totalPages - boundaries);
19
+ const shouldShowLeftDots = leftSiblingIndex > boundaries + 2;
20
+ const shouldShowRightDots = rightSiblingIndex < totalPages - (boundaries + 1);
21
+ if (!shouldShowLeftDots && shouldShowRightDots) {
22
+ const leftItemCount = siblings * 2 + boundaries + 2;
23
+ return [
24
+ ...range(1, leftItemCount),
25
+ "...",
26
+ ...range(totalPages - (boundaries - 1), totalPages)
27
+ ];
28
+ }
29
+ if (shouldShowLeftDots && !shouldShowRightDots) {
30
+ const rightItemCount = boundaries + 1 + 2 * siblings;
31
+ return [
32
+ ...range(1, boundaries),
33
+ "...",
34
+ ...range(totalPages - rightItemCount, totalPages)
35
+ ];
36
+ }
37
+ return [
38
+ ...range(1, boundaries),
39
+ "...",
40
+ ...range(leftSiblingIndex, rightSiblingIndex),
41
+ "...",
42
+ ...range(totalPages - boundaries + 1, totalPages)
43
+ ];
44
+ }, [
45
+ totalPages,
46
+ siblings,
47
+ activePage,
48
+ boundaries
49
+ ]),
50
+ active: activePage,
51
+ setPage
52
+ };
53
+ };
54
+ //#endregion
55
+ export { DOTS, usePagination };
@@ -0,0 +1,4 @@
1
+ //#region src/use-reduced-motion.d.ts
2
+ declare const useReducedMotion: () => boolean;
3
+ //#endregion
4
+ export { useReducedMotion };
@@ -0,0 +1,5 @@
1
+ import { useMediaQuery } from "./use-media-query.js";
2
+ //#region src/use-reduced-motion.ts
3
+ const useReducedMotion = () => useMediaQuery("(prefers-reduced-motion: reduce)");
4
+ //#endregion
5
+ export { useReducedMotion };
@@ -0,0 +1,5 @@
1
+ //#region src/use-scroll-direction.d.ts
2
+ type ScrollDirection = "up" | "down" | "unknown";
3
+ declare const useScrollDirection: () => ScrollDirection;
4
+ //#endregion
5
+ export { useScrollDirection };
@@ -0,0 +1,33 @@
1
+ import { useEffect, useEffectEvent, useRef, useState } from "react";
2
+ //#region src/use-scroll-direction.ts
3
+ const useScrollDirection = () => {
4
+ const lastScrollTopRef = useRef(0);
5
+ const [scrollDirection, setScrollDirection] = useState("unknown");
6
+ const isResizingRef = useRef(false);
7
+ const resizeTimerRef = useRef(void 0);
8
+ const handleScroll = useEffectEvent(() => {
9
+ if (isResizingRef.current) return;
10
+ const currentScrollTop = window.scrollY || document.documentElement.scrollTop;
11
+ setScrollDirection(currentScrollTop < lastScrollTopRef.current ? "up" : "down");
12
+ lastScrollTopRef.current = currentScrollTop;
13
+ });
14
+ useEffect(() => {
15
+ const handleResize = () => {
16
+ isResizingRef.current = true;
17
+ window.clearTimeout(resizeTimerRef.current);
18
+ resizeTimerRef.current = window.setTimeout(() => {
19
+ isResizingRef.current = false;
20
+ }, 300);
21
+ };
22
+ window.addEventListener("scroll", handleScroll);
23
+ window.addEventListener("resize", handleResize);
24
+ return () => {
25
+ window.removeEventListener("scroll", handleScroll);
26
+ window.removeEventListener("resize", handleResize);
27
+ clearTimeout(resizeTimerRef.current);
28
+ };
29
+ }, []);
30
+ return scrollDirection;
31
+ };
32
+ //#endregion
33
+ export { useScrollDirection };
@@ -0,0 +1,11 @@
1
+ //#region src/use-uncontrolled.d.ts
2
+ type UseUncontrolledOptions<T> = {
3
+ value?: T;
4
+ defaultValue?: T;
5
+ finalValue?: T;
6
+ onChange?: (value: T, ...payload: unknown[]) => void;
7
+ };
8
+ type UseUncontrolledReturnValue<T> = [T, (value: T, ...payload: unknown[]) => void, boolean];
9
+ declare const useUncontrolled: <T>({ value, defaultValue, finalValue, onChange }: UseUncontrolledOptions<T>) => UseUncontrolledReturnValue<T>;
10
+ //#endregion
11
+ export { type UseUncontrolledOptions, type UseUncontrolledReturnValue, useUncontrolled };
@@ -0,0 +1,21 @@
1
+ import { useState } from "react";
2
+ //#region src/use-uncontrolled.ts
3
+ const useUncontrolled = ({ value, defaultValue, finalValue, onChange = () => {} }) => {
4
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue !== void 0 ? defaultValue : finalValue);
5
+ const handleUncontrolledChange = (val, ...payload) => {
6
+ setUncontrolledValue(val);
7
+ onChange(val, ...payload);
8
+ };
9
+ if (value !== void 0) return [
10
+ value,
11
+ onChange,
12
+ true
13
+ ];
14
+ return [
15
+ uncontrolledValue,
16
+ handleUncontrolledChange,
17
+ false
18
+ ];
19
+ };
20
+ //#endregion
21
+ export { useUncontrolled };
@@ -0,0 +1,10 @@
1
+ //#region src/use-validated-state.d.ts
2
+ type UseValidatedStateValue<T> = {
3
+ value: T;
4
+ lastValidValue: T | undefined;
5
+ valid: boolean;
6
+ };
7
+ type UseValidatedStateReturnValue<T> = [UseValidatedStateValue<T>, (value: T) => void];
8
+ declare const useValidatedState: <T>(initialValue: T, validate: (value: T) => boolean, initialValidationState?: boolean) => UseValidatedStateReturnValue<T>;
9
+ //#endregion
10
+ export { type UseValidatedStateReturnValue, type UseValidatedStateValue, useValidatedState };
@@ -0,0 +1,22 @@
1
+ import { useCallback, useState } from "react";
2
+ //#region src/use-validated-state.ts
3
+ const useValidatedState = (initialValue, validate, initialValidationState) => {
4
+ const [state, setState] = useState(() => {
5
+ const valid = validate(initialValue);
6
+ return {
7
+ value: initialValue,
8
+ lastValidValue: valid ? initialValue : void 0,
9
+ valid: initialValidationState ?? valid
10
+ };
11
+ });
12
+ return [state, useCallback((value) => {
13
+ const valid = validate(value);
14
+ setState((previous) => ({
15
+ value,
16
+ lastValidValue: valid ? value : previous.lastValidValue,
17
+ valid
18
+ }));
19
+ }, [validate])];
20
+ };
21
+ //#endregion
22
+ export { useValidatedState };
@@ -0,0 +1,5 @@
1
+ //#region src/use-window-event.d.ts
2
+ type WindowEventListener<K extends string> = K extends keyof WindowEventMap ? (event: WindowEventMap[K]) => void : (event: CustomEvent) => void;
3
+ declare const useWindowEvent: <K extends string>(type: K, listener: WindowEventListener<K>, options?: boolean | AddEventListenerOptions) => void;
4
+ //#endregion
5
+ export { useWindowEvent };
@@ -0,0 +1,11 @@
1
+ import { useEffect, useEffectEvent } from "react";
2
+ //#region src/use-window-event.ts
3
+ const useWindowEvent = (type, listener, options) => {
4
+ const onEvent = useEffectEvent((event) => listener(event));
5
+ useEffect(() => {
6
+ window.addEventListener(type, onEvent, options);
7
+ return () => window.removeEventListener(type, onEvent, options);
8
+ }, [type, options]);
9
+ };
10
+ //#endregion
11
+ export { useWindowEvent };
@@ -0,0 +1,10 @@
1
+ //#region src/use-window-scroll.d.ts
2
+ type UseWindowScrollPosition = {
3
+ x: number;
4
+ y: number;
5
+ };
6
+ type UseWindowScrollTo = (position: Partial<UseWindowScrollPosition>) => void;
7
+ type UseWindowScrollReturnValue = [UseWindowScrollPosition, UseWindowScrollTo];
8
+ declare const useWindowScroll: () => UseWindowScrollReturnValue;
9
+ //#endregion
10
+ export { type UseWindowScrollPosition, type UseWindowScrollReturnValue, type UseWindowScrollTo, useWindowScroll };