@oxyhq/services
Version:
Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀
399 lines (382 loc) • 10.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useAsync = useAsync;
exports.useAsyncEffect = useAsyncEffect;
exports.useClickOutside = useClickOutside;
exports.useCounter = useCounter;
exports.useDebounce = useDebounce;
exports.useFormValidation = useFormValidation;
exports.useKeyPress = useKeyPress;
exports.useLocalStorage = useLocalStorage;
exports.useMediaQuery = useMediaQuery;
exports.useOnlineStatus = useOnlineStatus;
exports.usePrevious = usePrevious;
exports.useScrollPosition = useScrollPosition;
exports.useSessionStorage = useSessionStorage;
exports.useThrottle = useThrottle;
exports.useToggle = useToggle;
exports.useWindowSize = useWindowSize;
var _react = require("react");
/**
* React hook utilities for common patterns and state management
*/
/**
* Hook for managing async operations with loading, error, and data states
*/
function useAsync(asyncFn, deps = []) {
const [data, setData] = (0, _react.useState)(null);
const [loading, setLoading] = (0, _react.useState)(false);
const [error, setError] = (0, _react.useState)(null);
const execute = (0, _react.useCallback)(async () => {
setLoading(true);
setError(null);
try {
const result = await asyncFn();
setData(result);
return result;
} catch (err) {
const error = err instanceof Error ? err : new Error(String(err));
setError(error);
throw error;
} finally {
setLoading(false);
}
}, deps);
return {
data,
loading,
error,
execute
};
}
/**
* Hook for managing async operations that execute on mount
*/
function useAsyncEffect(asyncFn, deps = []) {
const [data, setData] = (0, _react.useState)(null);
const [loading, setLoading] = (0, _react.useState)(true);
const [error, setError] = (0, _react.useState)(null);
(0, _react.useEffect)(() => {
let mounted = true;
const execute = async () => {
try {
const result = await asyncFn();
if (mounted) {
setData(result);
setLoading(false);
}
} catch (err) {
if (mounted) {
const error = err instanceof Error ? err : new Error(String(err));
setError(error);
setLoading(false);
}
}
};
execute();
return () => {
mounted = false;
};
}, deps);
return {
data,
loading,
error
};
}
/**
* Hook for debounced values
*/
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = (0, _react.useState)(value);
(0, _react.useEffect)(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
/**
* Hook for throttled values
*/
function useThrottle(value, delay) {
const [throttledValue, setThrottledValue] = (0, _react.useState)(value);
const lastRun = (0, _react.useRef)(Date.now());
(0, _react.useEffect)(() => {
const handler = setTimeout(() => {
if (Date.now() - lastRun.current >= delay) {
setThrottledValue(value);
lastRun.current = Date.now();
}
}, delay - (Date.now() - lastRun.current));
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return throttledValue;
}
/**
* Hook for previous value
*/
function usePrevious(value) {
const ref = (0, _react.useRef)(undefined);
(0, _react.useEffect)(() => {
ref.current = value;
});
return ref.current;
}
/**
* Hook for boolean state with toggle
*/
function useToggle(initialValue = false) {
const [value, setValue] = (0, _react.useState)(initialValue);
const toggle = (0, _react.useCallback)(() => setValue(v => !v), []);
const setTrue = (0, _react.useCallback)(() => setValue(true), []);
const setFalse = (0, _react.useCallback)(() => setValue(false), []);
return {
value,
toggle,
setTrue,
setFalse,
setValue
};
}
/**
* Hook for counter state
*/
function useCounter(initialValue = 0) {
const [count, setCount] = (0, _react.useState)(initialValue);
const increment = (0, _react.useCallback)(() => setCount(c => c + 1), []);
const decrement = (0, _react.useCallback)(() => setCount(c => c - 1), []);
const reset = (0, _react.useCallback)(() => setCount(initialValue), [initialValue]);
const setValue = (0, _react.useCallback)(value => setCount(value), []);
return {
count,
increment,
decrement,
reset,
setValue
};
}
/**
* Hook for local storage
*/
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = (0, _react.useState)(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(`Error reading localStorage key "${key}":`, error);
return initialValue;
}
});
const setValue = (0, _react.useCallback)(value => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(`Error setting localStorage key "${key}":`, error);
}
}, [key, storedValue]);
return [storedValue, setValue];
}
/**
* Hook for session storage
*/
function useSessionStorage(key, initialValue) {
const [storedValue, setStoredValue] = (0, _react.useState)(() => {
try {
const item = window.sessionStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(`Error reading sessionStorage key "${key}":`, error);
return initialValue;
}
});
const setValue = (0, _react.useCallback)(value => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.sessionStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(`Error setting sessionStorage key "${key}":`, error);
}
}, [key, storedValue]);
return [storedValue, setValue];
}
/**
* Hook for window size
*/
function useWindowSize() {
const [windowSize, setWindowSize] = (0, _react.useState)({
width: window.innerWidth,
height: window.innerHeight
});
(0, _react.useEffect)(() => {
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight
});
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowSize;
}
/**
* Hook for scroll position
*/
function useScrollPosition() {
const [scrollPosition, setScrollPosition] = (0, _react.useState)(0);
(0, _react.useEffect)(() => {
const handleScroll = () => {
setScrollPosition(window.pageYOffset);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return scrollPosition;
}
/**
* Hook for online/offline status
*/
function useOnlineStatus() {
const [isOnline, setIsOnline] = (0, _react.useState)(navigator.onLine);
(0, _react.useEffect)(() => {
const handleOnline = () => setIsOnline(true);
const handleOffline = () => setIsOnline(false);
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
return isOnline;
}
/**
* Hook for media queries
*/
function useMediaQuery(query) {
const [matches, setMatches] = (0, _react.useState)(false);
(0, _react.useEffect)(() => {
const media = window.matchMedia(query);
if (media.matches !== matches) {
setMatches(media.matches);
}
const listener = () => setMatches(media.matches);
media.addEventListener('change', listener);
return () => media.removeEventListener('change', listener);
}, [matches, query]);
return matches;
}
/**
* Hook for keyboard events
*/
function useKeyPress(targetKey) {
const [keyPressed, setKeyPressed] = (0, _react.useState)(false);
(0, _react.useEffect)(() => {
const downHandler = ({
key
}) => {
if (key === targetKey) {
setKeyPressed(true);
}
};
const upHandler = ({
key
}) => {
if (key === targetKey) {
setKeyPressed(false);
}
};
window.addEventListener('keydown', downHandler);
window.addEventListener('keyup', upHandler);
return () => {
window.removeEventListener('keydown', downHandler);
window.removeEventListener('keyup', upHandler);
};
}, [targetKey]);
return keyPressed;
}
/**
* Hook for click outside detection
*/
function useClickOutside(ref, handler) {
(0, _react.useEffect)(() => {
const listener = event => {
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler();
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
}, [ref, handler]);
}
/**
* Hook for form validation
*/
function useFormValidation(initialValues, validationSchema) {
const [values, setValues] = (0, _react.useState)(initialValues);
const [errors, setErrors] = (0, _react.useState)({});
const [touched, setTouched] = (0, _react.useState)({});
const validate = (0, _react.useCallback)(valuesToValidate => {
return validationSchema(valuesToValidate);
}, [validationSchema]);
const setValue = (0, _react.useCallback)((field, value) => {
setValues(prev => ({
...prev,
[field]: value
}));
if (touched[field]) {
const newErrors = validate({
...values,
[field]: value
});
setErrors(prev => ({
...prev,
[field]: newErrors[field]
}));
}
}, [values, touched, validate]);
const setTouchedField = (0, _react.useCallback)(field => {
setTouched(prev => ({
...prev,
[field]: true
}));
const newErrors = validate(values);
setErrors(prev => ({
...prev,
[field]: newErrors[field]
}));
}, [values, validate]);
const isValid = (0, _react.useMemo)(() => {
const validationErrors = validate(values);
return Object.keys(validationErrors).length === 0;
}, [values, validate]);
return {
values,
errors,
touched,
isValid,
setValue,
setTouchedField,
setValues,
setErrors,
setTouched
};
}
//# sourceMappingURL=hookUtils.js.map