@reactuses/core
Version:
<div align = "center"> <h1 align = "center"> reactuse </h1> </div>
1,632 lines (1,581 loc) • 128 kB
JavaScript
import React, { useLayoutEffect, useEffect, useRef, useReducer, useState, useCallback, useMemo } from 'react';
import { isEqual, debounce, throttle } from 'lodash-es';
import Cookies from 'js-cookie';
import screenfull from 'screenfull';
import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js';
import { fetchEventSource } from '@microsoft/fetch-event-source';
var _window_navigator, _window;
function isFunction(val) {
return typeof val === 'function';
}
function isString(val) {
return typeof val === 'string';
}
const isDev = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
const isBrowser = typeof window !== 'undefined';
const isNavigator = typeof navigator !== 'undefined';
function noop() {}
const isIOS = isBrowser && ((_window = window) == null ? void 0 : (_window_navigator = _window.navigator) == null ? void 0 : _window_navigator.userAgent) && /iP(?:ad|hone|od)/.test(window.navigator.userAgent);
const useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;
const useLatest = (value)=>{
const ref = useRef(value);
useIsomorphicLayoutEffect(()=>{
ref.current = value;
}, [
value
]);
return ref;
};
function on(obj, ...args) {
if (obj && obj.addEventListener) {
obj.addEventListener(...args);
}
}
function off(obj, ...args) {
if (obj && obj.removeEventListener) {
obj.removeEventListener(...args);
}
}
const defaultWindow = typeof window !== 'undefined' ? window : undefined;
const defaultDocument = typeof document !== 'undefined' ? document : undefined;
const defaultOptions$1 = {};
function defaultOnError(e) {
console.error(e);
}
function getTargetElement(target, defaultElement) {
if (!isBrowser) {
return undefined;
}
if (!target) {
return defaultElement;
}
let targetElement;
if (isFunction(target)) {
targetElement = target();
} else if ('current' in target) {
targetElement = target.current;
} else {
targetElement = target;
}
return targetElement;
}
const updateReducer = (num)=>(num + 1) % 1000000;
function useUpdate() {
const [, update] = useReducer(updateReducer, 0);
return update;
}
const useCustomCompareEffect = (effect, deps, depsEqual)=>{
if (process.env.NODE_ENV !== 'production') {
if (!Array.isArray(deps) || !deps.length) {
console.warn('`useCustomCompareEffect` should not be used with no dependencies. Use React.useEffect instead.');
}
if (typeof depsEqual !== 'function') {
console.warn('`useCustomCompareEffect` should be used with depsEqual callback for comparing deps list');
}
}
const ref = useRef(undefined);
const forceUpdate = useUpdate();
if (!ref.current) {
ref.current = deps;
}
useIsomorphicLayoutEffect(()=>{
if (!depsEqual(deps, ref.current)) {
ref.current = deps;
forceUpdate();
}
});
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(effect, ref.current);
};
const useDeepCompareEffect = (effect, deps)=>{
if (process.env.NODE_ENV !== 'production') {
if (!Array.isArray(deps) || !deps.length) {
console.warn('`useDeepCompareEffect` should not be used with no dependencies. Use React.useEffect instead.');
}
}
useCustomCompareEffect(effect, deps, isEqual);
};
function useEventListener(eventName, handler, element, options = defaultOptions$1) {
const savedHandler = useLatest(handler);
useDeepCompareEffect(()=>{
const targetElement = getTargetElement(element, defaultWindow);
if (!(targetElement && targetElement.addEventListener)) {
return;
}
const eventListener = (event)=>savedHandler.current(event);
on(targetElement, eventName, eventListener, options);
return ()=>{
if (!(targetElement && targetElement.removeEventListener)) {
return;
}
off(targetElement, eventName, eventListener);
};
}, [
eventName,
element,
options
]);
}
const useMount = (fn)=>{
if (isDev) {
if (!isFunction(fn)) {
console.error(`useMount: parameter \`fn\` expected to be a function, but got "${typeof fn}".`);
}
}
useEffect(()=>{
fn == null ? void 0 : fn();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
};
const useActiveElement = ()=>{
const [active, setActive] = useState(null);
const listener = useCallback(()=>{
var _window;
setActive((_window = window) == null ? void 0 : _window.document.activeElement);
}, []);
useEventListener('blur', listener, defaultWindow, true);
useEventListener('focus', listener, defaultWindow, true);
useMount(()=>{
var _window;
setActive((_window = window) == null ? void 0 : _window.document.activeElement);
});
return active;
};
function useMountedState() {
const mountedRef = useRef(false);
const get = useCallback(()=>mountedRef.current, []);
useEffect(()=>{
mountedRef.current = true;
return ()=>{
mountedRef.current = false;
};
}, []);
return get;
}
function asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _async_to_generator$7(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
const useAsyncEffect = (effect, cleanup = noop, deps)=>{
const mounted = useMountedState();
useEffect(()=>{
const execute = /*#__PURE__*/ _async_to_generator$7(function*() {
if (!mounted()) {
return;
}
yield effect();
});
execute();
return ()=>{
cleanup();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, deps);
};
const listerOptions = {
passive: true
};
const useClickOutside = (target, handler, enabled = true)=>{
const savedHandler = useLatest(handler);
const listener = (event)=>{
if (!enabled) {
return;
}
const element = getTargetElement(target);
if (!element) {
return;
}
const elements = event.composedPath();
if (element === event.target || elements.includes(element)) {
return;
}
savedHandler.current(event);
};
useEventListener('mousedown', listener, defaultWindow, listerOptions);
useEventListener('touchstart', listener, defaultWindow, listerOptions);
};
function getInitialState$5(key, defaultValue) {
// Prevent a React hydration mismatch when a default value is provided.
if (defaultValue !== undefined) {
return defaultValue;
}
if (isBrowser) {
return Cookies.get(key);
}
if (process.env.NODE_ENV !== 'production') {
console.warn('`useCookie` When server side rendering, defaultValue should be defined to prevent a hydration mismatches.');
}
return '';
}
const useCookie = (key, options = defaultOptions$1, defaultValue)=>{
const [cookieValue, setCookieValue] = useState(getInitialState$5(key, defaultValue));
useEffect(()=>{
const getStoredValue = ()=>{
const raw = Cookies.get(key);
if (raw !== undefined && raw !== null) {
return raw;
} else {
if (defaultValue === undefined) {
Cookies.remove(key);
} else {
Cookies.set(key, defaultValue, options);
}
return defaultValue;
}
};
setCookieValue(getStoredValue());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
defaultValue,
key,
JSON.stringify(options)
]);
const updateCookie = useCallback((newValue)=>{
const value = isFunction(newValue) ? newValue(cookieValue) : newValue;
if (value === undefined) {
Cookies.remove(key);
} else {
Cookies.set(key, value, options);
}
setCookieValue(value);
}, // eslint-disable-next-line react-hooks/exhaustive-deps
[
key,
cookieValue,
JSON.stringify(options)
]);
const refreshCookie = useCallback(()=>{
const cookieValue = Cookies.get(key);
if (isString(cookieValue)) {
setCookieValue(cookieValue);
}
}, [
key
]);
return [
cookieValue,
updateCookie,
refreshCookie
];
};
/**
* keep function reference immutable
*/ const useEvent = (fn)=>{
if (isDev) {
if (!isFunction(fn)) {
console.error(`useEvent expected parameter is a function, got ${typeof fn}`);
}
}
const handlerRef = useRef(fn);
useIsomorphicLayoutEffect(()=>{
handlerRef.current = fn;
}, [
fn
]);
return useCallback((...args)=>{
const fn = handlerRef.current;
return fn(...args);
}, []);
};
const useInterval = (callback, delay, options = defaultOptions$1)=>{
const { immediate, controls } = options;
const savedCallback = useLatest(callback);
const isActive = useRef(false);
const timer = useRef(null);
const clean = ()=>{
timer.current && clearInterval(timer.current);
};
const resume = useEvent(()=>{
isActive.current = true;
timer.current = setInterval(()=>savedCallback.current(), delay || 0);
});
const pause = useEvent(()=>{
isActive.current = false;
clean();
});
useEffect(()=>{
if (immediate) {
savedCallback.current();
}
if (controls) {
return;
}
if (delay !== null) {
resume();
return ()=>{
clean();
};
}
return undefined;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
delay,
immediate
]);
return {
isActive,
pause,
resume
};
};
function padZero(time) {
return `${time}`.length < 2 ? `0${time}` : `${time}`;
}
function getHMSTime(timeDiff) {
if (timeDiff <= 0) {
return [
'00',
'00',
'00'
];
}
if (timeDiff > 100 * 3600) {
return [
'99',
'59',
'59'
];
}
const hour = Math.floor(timeDiff / 3600);
const minute = Math.floor((timeDiff - hour * 3600) / 60);
const second = timeDiff - hour * 3600 - minute * 60;
return [
padZero(hour),
padZero(minute),
padZero(second)
];
}
const useCountDown = (time, format = getHMSTime, callback)=>{
const [remainTime, setRemainTime] = useState(time);
const [delay, setDelay] = useState(1000);
useInterval(()=>{
if (remainTime <= 0) {
setDelay(null);
return;
}
setRemainTime(remainTime - 1);
}, delay);
useEffect(()=>{
if (time > 0 && remainTime <= 0) {
callback && callback();
}
}, [
callback,
remainTime,
time
]);
const [hour, minute, secoud] = format(remainTime);
return [
hour,
minute,
secoud
];
};
const useCounter = (initialValue = 0, max = null, min = null)=>{
// avoid exec init code every render
const initFunc = ()=>{
let init = typeof initialValue === 'function' ? initialValue() : initialValue;
typeof init !== 'number' && console.error(`initialValue has to be a number, got ${typeof initialValue}`);
if (typeof min === 'number') {
init = Math.max(init, min);
} else if (min !== null) {
console.error(`min has to be a number, got ${typeof min}`);
}
if (typeof max === 'number') {
init = Math.min(init, max);
} else if (max !== null) {
console.error(`max has to be a number, got ${typeof max}`);
}
return init;
};
const [value, setValue] = useState(initFunc);
const set = useEvent((newState)=>{
setValue((v)=>{
let nextValue = typeof newState === 'function' ? newState(v) : newState;
if (typeof min === 'number') {
nextValue = Math.max(nextValue, min);
}
if (typeof max === 'number') {
nextValue = Math.min(nextValue, max);
}
return nextValue;
});
});
const inc = (delta = 1)=>{
set((value)=>value + delta);
};
const dec = (delta = 1)=>{
set((value)=>value - delta);
};
const reset = ()=>{
set(initFunc);
};
return [
value,
set,
inc,
dec,
reset
];
};
const defaultOptions = {
observe: false
};
function getInitialState$4(defaultValue) {
// Prevent a React hydration mismatch when a default value is provided.
if (defaultValue !== undefined) {
return defaultValue;
}
if (isBrowser) {
return '';
}
if (process.env.NODE_ENV !== 'production') {
console.warn('`useCssVar` When server side rendering, defaultValue should be defined to prevent a hydration mismatches.');
}
return '';
}
const useCssVar = (prop, target, defaultValue, options = defaultOptions)=>{
const { observe } = options;
const [variable, setVariable] = useState(getInitialState$4(defaultValue));
const observerRef = useRef();
const set = useCallback((v)=>{
const element = getTargetElement(target);
if (element == null ? void 0 : element.style) {
element == null ? void 0 : element.style.setProperty(prop, v);
setVariable(v);
}
}, [
prop,
target
]);
const updateCssVar = useCallback(()=>{
const element = getTargetElement(target);
if (element) {
var _window_getComputedStyle_getPropertyValue;
const value = (_window_getComputedStyle_getPropertyValue = window.getComputedStyle(element).getPropertyValue(prop)) == null ? void 0 : _window_getComputedStyle_getPropertyValue.trim();
setVariable(value);
}
}, [
target,
prop
]);
useEffect(()=>{
var _window_getComputedStyle_getPropertyValue;
const element = getTargetElement(target);
if (!element) {
return;
}
const value = (_window_getComputedStyle_getPropertyValue = window.getComputedStyle(element).getPropertyValue(prop)) == null ? void 0 : _window_getComputedStyle_getPropertyValue.trim();
/** if var don't has value and defaultValue exist */ if (!value && defaultValue) {
set(defaultValue);
} else {
updateCssVar();
}
if (!observe) {
return;
}
observerRef.current = new MutationObserver(updateCssVar);
observerRef.current.observe(element, {
attributeFilter: [
'style',
'class'
]
});
return ()=>{
if (observerRef.current) {
observerRef.current.disconnect();
}
};
}, [
observe,
target,
updateCssVar,
set,
defaultValue,
prop
]);
return [
variable,
set
];
};
const useCycleList = (list, i = 0)=>{
const [index, setIndex] = useState(i);
const set = (i)=>{
const length = list.length;
const nextIndex = ((index + i) % length + length) % length;
setIndex(nextIndex);
};
const next = (i = 1)=>{
set(i);
};
const prev = (i = 1)=>{
set(-i);
};
return [
list[index],
next,
prev
];
};
function guessSerializerType(rawInit) {
return rawInit == null || rawInit === undefined ? 'any' : rawInit instanceof Set ? 'set' : rawInit instanceof Map ? 'map' : rawInit instanceof Date ? 'date' : typeof rawInit === 'boolean' ? 'boolean' : typeof rawInit === 'string' ? 'string' : typeof rawInit === 'object' ? 'object' : Array.isArray(rawInit) ? 'object' : !Number.isNaN(rawInit) ? 'number' : 'any';
}
const StorageSerializers = {
boolean: {
read: (v)=>v === 'true',
write: (v)=>String(v)
},
object: {
read: (v)=>JSON.parse(v),
write: (v)=>JSON.stringify(v)
},
number: {
read: (v)=>Number.parseFloat(v),
write: (v)=>String(v)
},
any: {
read: (v)=>v,
write: (v)=>String(v)
},
string: {
read: (v)=>v,
write: (v)=>String(v)
},
map: {
read: (v)=>new Map(JSON.parse(v)),
write: (v)=>JSON.stringify(Array.from(v.entries()))
},
set: {
read: (v)=>new Set(JSON.parse(v)),
write: (v)=>JSON.stringify(Array.from(v))
},
date: {
read: (v)=>new Date(v),
write: (v)=>v.toISOString()
}
};
function getInitialState$3(key, defaultValue, storage, serializer, onError) {
// Prevent a React hydration mismatch when a default value is provided.
if (defaultValue !== undefined) {
return defaultValue;
}
if (isBrowser) {
try {
const raw = storage == null ? void 0 : storage.getItem(key);
if (raw !== undefined && raw !== null) {
return serializer == null ? void 0 : serializer.read(raw);
}
return null;
} catch (error) {
onError == null ? void 0 : onError(error);
}
}
// A default value has not been provided, and you are rendering on the server, warn of a possible hydration mismatch when defaulting to false.
if (process.env.NODE_ENV !== 'production') {
console.warn('`createStorage` When server side rendering, defaultValue should be defined to prevent a hydration mismatches.');
}
return null;
}
function useStorage(key, defaultValue, getStorage = ()=>isBrowser ? sessionStorage : undefined, options = defaultOptions$1) {
let storage;
const { onError = defaultOnError, effectStorageValue, mountStorageValue, listenToStorageChanges = true } = options;
const storageValue = mountStorageValue != null ? mountStorageValue : effectStorageValue;
try {
storage = getStorage();
} catch (err) {
onError(err);
}
const type = guessSerializerType(defaultValue);
var _options_serializer;
const serializer = (_options_serializer = options.serializer) != null ? _options_serializer : StorageSerializers[type];
const [state, setState] = useState(getInitialState$3(key, defaultValue, storage, serializer, onError));
useDeepCompareEffect(()=>{
var _ref;
const data = (_ref = storageValue ? isFunction(storageValue) ? storageValue() : storageValue : defaultValue) != null ? _ref : null;
const getStoredValue = ()=>{
try {
const raw = storage == null ? void 0 : storage.getItem(key);
if (raw !== undefined && raw !== null) {
return serializer.read(raw);
} else {
storage == null ? void 0 : storage.setItem(key, serializer.write(data));
return data;
}
} catch (e) {
onError(e);
}
};
setState(getStoredValue());
}, [
key,
serializer,
storage,
onError,
storageValue
]);
const updateState = useEvent((valOrFunc)=>{
const currentState = isFunction(valOrFunc) ? valOrFunc(state) : valOrFunc;
setState(currentState);
if (currentState === null) {
storage == null ? void 0 : storage.removeItem(key);
} else {
try {
storage == null ? void 0 : storage.setItem(key, serializer.write(currentState));
} catch (e) {
onError(e);
}
}
});
const listener = useEvent(()=>{
try {
const raw = storage == null ? void 0 : storage.getItem(key);
if (raw !== undefined && raw !== null) {
updateState(serializer.read(raw));
} else {
updateState(null);
}
} catch (e) {
onError(e);
}
});
useEffect(()=>{
if (listenToStorageChanges) {
window.addEventListener('storage', listener);
return ()=>window.removeEventListener('storage', listener);
}
return ()=>{};
}, [
listenToStorageChanges,
listener
]);
return [
state,
updateState
];
}
function value() {
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
const useDarkMode = (options)=>{
const { selector = 'html', attribute = 'class', classNameDark = '', classNameLight = '', storageKey = 'reactuses-color-scheme', storage = ()=>isBrowser ? localStorage : undefined, defaultValue = false } = options;
const [dark, setDark] = useStorage(storageKey, defaultValue, storage, {
mountStorageValue: value
});
useEffect(()=>{
var _window;
const element = (_window = window) == null ? void 0 : _window.document.querySelector(selector);
if (!element) {
return;
}
if (attribute === 'class') {
dark && classNameDark && element.classList.add(classNameDark);
!dark && classNameLight && element.classList.add(classNameLight);
} else {
dark && classNameDark && element.setAttribute(attribute, classNameDark);
!dark && classNameLight && element.setAttribute(attribute, classNameLight);
}
return ()=>{
if (!element) {
return;
}
if (attribute === 'class') {
dark && classNameDark && element.classList.remove(classNameDark);
!dark && classNameLight && element.classList.remove(classNameLight);
} else {
dark && classNameDark && element.removeAttribute(attribute);
!dark && classNameLight && element.removeAttribute(attribute);
}
};
}, [
attribute,
classNameDark,
classNameLight,
dark,
selector
]);
return [
dark,
()=>setDark((dark)=>!dark),
setDark
];
};
function useUnmount(fn) {
if (isDev) {
if (!isFunction(fn)) {
console.error(`useUnmount expected parameter is a function, got ${typeof fn}`);
}
}
const fnRef = useLatest(fn);
useEffect(()=>()=>{
fnRef.current();
}, [
fnRef
]);
}
const useDebounceFn = (fn, wait, options)=>{
if (isDev) {
if (!isFunction(fn)) {
console.error(`useDebounceFn expected parameter is a function, got ${typeof fn}`);
}
}
const fnRef = useLatest(fn);
const debounced = useMemo(()=>debounce((...args)=>{
return fnRef.current(...args);
}, wait, options), // eslint-disable-next-line react-hooks/exhaustive-deps
[
JSON.stringify(options),
wait
]);
useUnmount(()=>{
debounced.cancel();
});
return {
run: debounced,
cancel: debounced.cancel,
flush: debounced.flush
};
};
const useDebounce = (value, wait, options)=>{
const [debounced, setDebounced] = useState(value);
const { run } = useDebounceFn(()=>{
setDebounced(value);
}, wait, options);
useEffect(()=>{
run();
}, [
run,
value
]);
return debounced;
};
function getInitialState$2(defaultValue) {
// Prevent a React hydration mismatch when a default value is provided.
if (defaultValue !== undefined) {
return defaultValue;
}
if (isBrowser) {
return document.visibilityState;
}
if (process.env.NODE_ENV !== 'production') {
console.warn('`useDocumentVisibility` When server side rendering, defaultValue should be defined to prevent a hydration mismatches.');
}
return 'visible';
}
function useDocumentVisibility(defaultValue) {
const [visible, setVisible] = useState(getInitialState$2(defaultValue));
useEventListener('visibilitychange', ()=>{
setVisible(document.visibilityState);
}, ()=>document);
useEffect(()=>{
setVisible(document.visibilityState);
}, []);
return visible;
}
const useDoubleClick = ({ target, latency = 300, onSingleClick = ()=>{}, onDoubleClick = ()=>{} })=>{
const handle = useCallback((onSingleClick, onDoubleClick)=>{
let count = 0;
return (e)=>{
// prevent ios double click slide
if (e.type === 'touchend') {
e.stopPropagation();
e.preventDefault();
}
count += 1;
setTimeout(()=>{
if (count === 1) {
onSingleClick(e);
} else if (count === 2) {
onDoubleClick(e);
}
count = 0;
}, latency);
};
}, [
latency
]);
const handleClick = handle(onSingleClick, onDoubleClick);
const handleTouchEnd = handle(onSingleClick, onDoubleClick);
useEventListener('click', handleClick, target);
useEventListener('touchend', handleTouchEnd, target, {
passive: false
});
};
function isScrollX(node) {
if (!node) {
return false;
}
return getComputedStyle(node).overflowX === 'auto' || getComputedStyle(node).overflowX === 'scroll';
}
function isScrollY(node) {
if (!node) {
return false;
}
return getComputedStyle(node).overflowY === 'auto' || getComputedStyle(node).overflowY === 'scroll';
}
const useDraggable = (target, options = {})=>{
const { draggingElement, containerElement } = options;
var _options_handle;
const draggingHandle = (_options_handle = options.handle) != null ? _options_handle : target;
var _options_initialValue;
const [position, setPositon] = useState((_options_initialValue = options.initialValue) != null ? _options_initialValue : {
x: 0,
y: 0
});
useDeepCompareEffect(()=>{
var _options_initialValue;
setPositon((_options_initialValue = options.initialValue) != null ? _options_initialValue : {
x: 0,
y: 0
});
}, [
options.initialValue
]);
const [pressedDelta, setPressedDelta] = useState();
const filterEvent = (e)=>{
if (options.pointerTypes) {
return options.pointerTypes.includes(e.pointerType);
}
return true;
};
const handleEvent = (e)=>{
if (options.preventDefault) {
e.preventDefault();
}
if (options.stopPropagation) {
e.stopPropagation();
}
};
const start = (e)=>{
var _container_getBoundingClientRect;
const element = getTargetElement(target);
if (!filterEvent(e) || !element) {
return;
}
if (options.exact && e.target !== element) {
return;
}
const container = getTargetElement(containerElement);
const containerRect = container == null ? void 0 : (_container_getBoundingClientRect = container.getBoundingClientRect) == null ? void 0 : _container_getBoundingClientRect.call(container);
const targetRect = element.getBoundingClientRect();
const pos = {
x: e.clientX - (container && containerRect ? targetRect.left - (containerRect == null ? void 0 : containerRect.left) + container.scrollLeft : targetRect.left),
y: e.clientY - (container && containerRect ? targetRect.top - containerRect.top + container.scrollTop : targetRect.top)
};
if ((options.onStart == null ? void 0 : options.onStart.call(options, pos, e)) === false) {
return;
}
setPressedDelta(pos);
handleEvent(e);
};
const move = (e)=>{
const element = getTargetElement(target);
if (!filterEvent(e) || !element) {
return;
}
if (!pressedDelta) {
return;
}
const container = getTargetElement(containerElement);
const targetRect = element.getBoundingClientRect();
let { x, y } = position;
x = e.clientX - pressedDelta.x;
y = e.clientY - pressedDelta.y;
if (container) {
const containerWidth = isScrollX(container) ? container.scrollWidth : container.clientWidth;
const containerHeight = isScrollY(container) ? container.scrollHeight : container.clientHeight;
x = Math.min(Math.max(0, x), containerWidth - targetRect.width);
y = Math.min(Math.max(0, y), containerHeight - targetRect.height);
}
setPositon({
x,
y
});
options.onMove == null ? void 0 : options.onMove.call(options, position, e);
handleEvent(e);
};
const end = (e)=>{
if (!filterEvent(e)) {
return;
}
if (!pressedDelta) {
return;
}
setPressedDelta(undefined);
options.onEnd == null ? void 0 : options.onEnd.call(options, position, e);
handleEvent(e);
};
useEventListener('pointerdown', start, draggingHandle, true);
useEventListener('pointermove', move, draggingElement, true);
useEventListener('pointerup', end, draggingElement, true);
return [
position.x,
position.y,
!!pressedDelta,
setPositon
];
};
const useDropZone = (target, onDrop)=>{
const [over, setOver] = useState(false);
const counter = useRef(0);
useEventListener('dragenter', (event)=>{
event.preventDefault();
counter.current += 1;
setOver(true);
}, target);
useEventListener('dragover', (event)=>{
event.preventDefault();
}, target);
useEventListener('dragleave', (event)=>{
event.preventDefault();
counter.current -= 1;
if (counter.current === 0) {
setOver(false);
}
}, target);
useEventListener('drop', (event)=>{
var _event_dataTransfer;
event.preventDefault();
counter.current = 0;
setOver(false);
var _event_dataTransfer_files;
const files = Array.from((_event_dataTransfer_files = (_event_dataTransfer = event.dataTransfer) == null ? void 0 : _event_dataTransfer.files) != null ? _event_dataTransfer_files : []);
onDrop == null ? void 0 : onDrop(files.length === 0 ? null : files);
}, target);
return over;
};
const useResizeObserver = (target, callback, options = defaultOptions$1)=>{
const savedCallback = useLatest(callback);
const observerRef = useRef();
const stop = useCallback(()=>{
if (observerRef.current) {
observerRef.current.disconnect();
}
}, []);
useDeepCompareEffect(()=>{
const element = getTargetElement(target);
if (!element) {
return;
}
observerRef.current = new ResizeObserver(savedCallback.current);
observerRef.current.observe(element, options);
return stop;
}, [
savedCallback,
stop,
target,
options
]);
return stop;
};
const useElementBounding = (target, options = defaultOptions$1)=>{
const { reset = true, windowResize = true, windowScroll = true, immediate = true } = options;
const [height, setHeight] = useState(0);
const [bottom, setBottom] = useState(0);
const [left, setLeft] = useState(0);
const [right, setRight] = useState(0);
const [top, setTop] = useState(0);
const [width, setWidth] = useState(0);
const [x, setX] = useState(0);
const [y, setY] = useState(0);
const update = useEvent(()=>{
const element = getTargetElement(target);
if (!element) {
if (reset) {
setHeight(0);
setBottom(0);
setLeft(0);
setRight(0);
setTop(0);
setWidth(0);
setX(0);
setY(0);
}
return;
}
const rect = element.getBoundingClientRect();
setHeight(rect.height);
setBottom(rect.bottom);
setLeft(rect.left);
setRight(rect.right);
setTop(rect.top);
setWidth(rect.width);
setX(rect.x);
setY(rect.y);
});
useResizeObserver(target, update);
useEffect(()=>{
if (immediate) {
update();
}
}, [
immediate,
update
]);
useEffect(()=>{
if (windowScroll) {
window.addEventListener('scroll', update, {
passive: true
});
}
if (windowResize) {
window.addEventListener('resize', update, {
passive: true
});
}
return ()=>{
if (windowScroll) {
window.removeEventListener('scroll', update);
}
if (windowResize) {
window.removeEventListener('resize', update);
}
};
}, [
update,
windowResize,
windowScroll
]);
return {
height,
bottom,
left,
right,
top,
width,
x,
y,
update
};
};
const useElementSize = (target, options = defaultOptions$1)=>{
const { box = 'content-box' } = options;
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);
useResizeObserver(target, ([entry])=>{
const boxSize = box === 'border-box' ? entry.borderBoxSize : box === 'content-box' ? entry.contentBoxSize : entry.devicePixelContentBoxSize;
if (boxSize) {
setWidth(boxSize.reduce((acc, { inlineSize })=>acc + inlineSize, 0));
setHeight(boxSize.reduce((acc, { blockSize })=>acc + blockSize, 0));
} else {
// fallback
setWidth(entry.contentRect.width);
setHeight(entry.contentRect.height);
}
}, options);
return [
width,
height
];
};
const useIntersectionObserver = (target, callback, options = defaultOptions$1)=>{
const savedCallback = useLatest(callback);
const observerRef = useRef();
const stop = useCallback(()=>{
if (observerRef.current) {
observerRef.current.disconnect();
}
}, []);
useDeepCompareEffect(()=>{
const element = getTargetElement(target);
if (!element) {
return;
}
observerRef.current = new IntersectionObserver(savedCallback.current, options);
observerRef.current.observe(element);
return stop;
}, [
options
]);
return stop;
};
const useElementVisibility = (target, options = defaultOptions$1)=>{
const [visible, setVisible] = useState(false);
const callback = useCallback((entries)=>{
const rect = entries[0].boundingClientRect;
setVisible(rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.left <= (window.innerWidth || document.documentElement.clientWidth) && rect.bottom >= 0 && rect.right >= 0);
}, []);
const stop = useIntersectionObserver(target, callback, options);
return [
visible,
stop
];
};
function useEventEmitter() {
const listeners = useRef([]);
const _disposed = useRef(false);
const _event = useRef((listener)=>{
listeners.current.push(listener);
const disposable = {
dispose: ()=>{
if (!_disposed.current) {
for(let i = 0; i < listeners.current.length; i++){
if (listeners.current[i] === listener) {
listeners.current.splice(i, 1);
return;
}
}
}
}
};
return disposable;
});
const fire = (arg1, arg2)=>{
const queue = [];
for(let i = 0; i < listeners.current.length; i++){
queue.push(listeners.current[i]);
}
for(let i = 0; i < queue.length; i++){
queue[i].call(undefined, arg1, arg2);
}
};
const dispose = ()=>{
if (listeners.current.length !== 0) {
listeners.current.length = 0;
}
_disposed.current = true;
};
return [
_event.current,
fire,
dispose
];
}
function useSupported(callback, sync = false) {
const [supported, setSupported] = useState(false);
const effect = sync ? useIsomorphicLayoutEffect : useEffect;
effect(()=>{
setSupported(Boolean(callback()));
}, []);
return supported;
}
function asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _async_to_generator$6(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
const useEyeDropper = ()=>{
const isSupported = useSupported(()=>typeof window !== 'undefined' && 'EyeDropper' in window, true);
const open = useCallback(/*#__PURE__*/ _async_to_generator$6(function*(options = {}) {
if (!isSupported) {
return {
sRGBHex: ''
};
}
const eyeDropper = new window.EyeDropper();
return eyeDropper.open(options);
}), [
isSupported
]);
return [
isSupported,
open
];
};
function useFavicon(href, baseUrl = '', rel = 'icon') {
useEffect(()=>{
const url = `${baseUrl}${href}`;
const element = document.head.querySelectorAll(`link[rel*="${rel}"]`);
element.forEach((el)=>el.href = url);
if (element.length === 0) {
const link = document.createElement('link');
link.rel = rel;
link.href = url;
document.getElementsByTagName('head')[0].appendChild(link);
}
}, [
baseUrl,
href,
rel
]);
}
function asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _async_to_generator$5(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _extends$3() {
_extends$3 = Object.assign || function(target) {
for(var i = 1; i < arguments.length; i++){
var source = arguments[i];
for(var key in source){
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends$3.apply(this, arguments);
}
const DEFAULT_OPTIONS = {
multiple: true,
accept: '*'
};
const useFileDialog = (options = defaultOptions$1)=>{
const [files, setFiles] = useState(null);
const inputRef = useRef();
const fileOpenPromiseRef = useRef(null);
const resolveFileOpenPromiseRef = useRef();
const initFn = useCallback(()=>{
if (typeof document === 'undefined') {
return undefined;
}
const input = document.createElement('input');
input.type = 'file';
input.onchange = (event)=>{
const result = event.target;
setFiles(result.files);
resolveFileOpenPromiseRef.current == null ? void 0 : resolveFileOpenPromiseRef.current.call(resolveFileOpenPromiseRef, result.files);
};
return input;
}, []);
inputRef.current = initFn();
const open = /*#__PURE__*/ _async_to_generator$5(function*(localOptions) {
if (!inputRef.current) {
return;
}
const _options = _extends$3({}, DEFAULT_OPTIONS, options, localOptions);
inputRef.current.multiple = _options.multiple;
inputRef.current.accept = _options.accept;
inputRef.current.capture = _options.capture;
fileOpenPromiseRef.current = new Promise((resolve)=>{
resolveFileOpenPromiseRef.current = resolve;
});
inputRef.current.click();
return fileOpenPromiseRef.current;
});
const reset = ()=>{
setFiles(null);
resolveFileOpenPromiseRef.current == null ? void 0 : resolveFileOpenPromiseRef.current.call(resolveFileOpenPromiseRef, null);
if (inputRef.current) {
inputRef.current.value = '';
}
};
return [
files,
open,
reset
];
};
const useFirstMountState = ()=>{
const isFirst = useRef(true);
if (isFirst.current) {
isFirst.current = false;
return true;
}
return isFirst.current;
};
const useFocus = (target, initialValue = false)=>{
const [focus, innerSetFocus] = useState(initialValue);
useEventListener('focus', ()=>innerSetFocus(true), target);
useEventListener('blur', ()=>innerSetFocus(false), target);
const setFocus = (value)=>{
const element = getTargetElement(target);
if (!element) {
return;
}
if (!value) {
element.blur();
} else if (value) {
element.focus();
}
};
useMount(()=>{
setFocus(focus);
});
return [
focus,
setFocus
];
};
const useRafFn = (callback, initiallyActive = true)=>{
const raf = useRef(null);
const rafActivity = useRef(false);
const rafCallback = useLatest(callback);
const step = useCallback((time)=>{
if (rafActivity.current) {
rafCallback.current(time);
raf.current = requestAnimationFrame(step);
}
}, [
rafCallback
]);
const result = useMemo(()=>[
()=>{
// stop
if (rafActivity.current) {
rafActivity.current = false;
raf.current && cancelAnimationFrame(raf.current);
}
},
()=>{
// start
if (!rafActivity.current) {
rafActivity.current = true;
raf.current = requestAnimationFrame(step);
}
},
()=>rafActivity.current
], [
step
]);
useEffect(()=>{
if (initiallyActive) {
result[1]();
}
return result[0];
}, [
initiallyActive,
result
]);
return result;
};
function useFps(options = defaultOptions$1) {
const [fps, setFps] = useState(0);
var _options_every;
const every = (_options_every = options.every) != null ? _options_every : 10;
const last = useRef(performance.now());
const ticks = useRef(0);
useRafFn(()=>{
ticks.current += 1;
if (ticks.current >= every) {
const now = performance.now();
const diff = now - last.current;
setFps(Math.round(1000 / (diff / ticks.current)));
last.current = now;
ticks.current = 0;
}
});
return fps;
}
const useFullscreen = (target, options = defaultOptions$1)=>{
const { onExit, onEnter } = options;
const [state, setState] = useState(false);
const onChange = ()=>{
if (screenfull.isEnabled) {
const { isFullscreen } = screenfull;
if (isFullscreen) {
onEnter == null ? void 0 : onEnter();
} else {
screenfull.off('change', onChange);
onExit == null ? void 0 : onExit();
}
setState(isFullscreen);
}
};
const enterFullscreen = ()=>{
const el = getTargetElement(target);
if (!el) {
return;
}
if (screenfull.isEnabled) {
try {
screenfull.request(el);
screenfull.on('change', onChange);
} catch (error) {
console.error(error);
}
}
};
const exitFullscreen = ()=>{
if (screenfull.isEnabled) {
screenfull.exit();
}
};
const toggleFullscreen = ()=>{
if (state) {
exitFullscreen();
} else {
enterFullscreen();
}
};
useUnmount(()=>{
if (screenfull.isEnabled) {
screenfull.off('change', onChange);
}
});
return [
state,
{
enterFullscreen: useEvent(enterFullscreen),
exitFullscreen: useEvent(exitFullscreen),
toggleFullscreen: useEvent(toggleFullscreen),
isEnabled: screenfull.isEnabled
}
];
};
const initCoord = {
accuracy: 0,
latitude: Number.POSITIVE_INFINITY,
longitude: Number.POSITIVE_INFINITY,
altitude: null,
altitudeAccuracy: null,
heading: null,
speed: null
};
const useGeolocation = (options = defaultOptions$1)=>{
const { enableHighAccuracy = true, maximumAge = 30000, timeout = 27000 } = options;
const isSupported = useSupported(()=>navigator && 'geolocation' in navigator);
const [coordinates, setCoordinates] = useState(initCoord);
const [locatedAt, setLocatedAt] = useState(null);
const [error, setError] = useState(null);
const updatePosition = useCallback((position)=>{
setCoordinates(position.coords);
setLocatedAt(position.timestamp);
setError(null);
}, []);
const updateError = useCallback((err)=>{
setCoordinates(initCoord);
setLocatedAt(null);
setError(err);
}, []);
useEffect(()=>{
if (!isSupported) {
return;
}
navigator.geolocation.getCurrentPosition(updatePosition, updateError);
const watchId = navigator.geolocation.watchPosition(updatePosition, updateError, {
enableHighAccuracy,
maximumAge,
timeout
});
return ()=>{
if (watchId) {
navigator.geolocation.clearWatch(watchId);
}
};
}, [
enableHighAccuracy,
isSupported,
maximumAge,
timeout,
updateError,
updatePosition
]);
return {
coordinates,
locatedAt,
error,
isSupported
};
};
const useHover = (target)=>{
const [hovered, setHovered] = useState(false);
const onMouseEnter = useCallback(()=>setHovered(true), []);
const onMouseLeave = useCallback(()=>setHovered(false), []);
useEventListener('mouseenter', onMouseEnter, target);
useEventListener('mouseleave', onMouseLeave, target);
return hovered;
};
const defaultEvents$1 = [
'mousemove',
'mousedown',
'resize',
'keydown',
'touchstart',
'wheel'
];
const oneMinute = 60e3;
const useIdle = (ms = oneMinute, initialState = false, events = defaultEvents$1)=>{
const [state, setState] = useState(initialState);
useEffect(()=>{
let mounted = true;
let timeout;
let localState = state;
const set = (newState)=>{
if (mounted) {
localState = newState;
setState(newState);
}
};
const onEvent = throttle(()=>{
if (localState) {
set(false);
}
clearTimeout(timeout);
timeout = setTimeout(()=>set(true), ms);
}, 50);
const onVisibility = ()=>{
if (!document.hidden) {
onEvent();
}
};
for(let i = 0; i < events.length; i++){
on(window, events[i], onEvent);
}
on(document, 'visibilitychange', onVisibility);
timeout = setTimeout(()=>set(true)