@mantine᜵hooks-umd

UMD of @mantine/hooks

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/499180/1510107/%40mantine%E1%9C%B5hooks-umd.js

  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
  3. typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MantineHooks = {}, global.React));
  5. })(this, (function (exports, React) { 'use strict';
  6. function clamp(value, min, max) {
  7. if (min === void 0 && max === void 0) {
  8. return value;
  9. }
  10. if (min !== void 0 && max === void 0) {
  11. return Math.max(value, min);
  12. }
  13. if (min === void 0 && max !== void 0) {
  14. return Math.min(value, max);
  15. }
  16. return Math.min(Math.max(value, min), max);
  17. }
  18. function lowerFirst(value) {
  19. return typeof value !== "string" ? "" : value.charAt(0).toLowerCase() + value.slice(1);
  20. }
  21. function randomId(prefix = "mantine-") {
  22. return `${prefix}${Math.random().toString(36).slice(2, 11)}`;
  23. }
  24. function range(start, end) {
  25. const length = Math.abs(end - start) + 1;
  26. const reversed = start > end;
  27. if (!reversed) {
  28. return Array.from({ length }, (_, index) => index + start);
  29. }
  30. return Array.from({ length }, (_, index) => start - index);
  31. }
  32. function shallowEqual(a, b) {
  33. if (a === b) {
  34. return true;
  35. }
  36. if (!(a instanceof Object) || !(b instanceof Object)) {
  37. return false;
  38. }
  39. const keys = Object.keys(a);
  40. const { length } = keys;
  41. if (length !== Object.keys(b).length) {
  42. return false;
  43. }
  44. for (let i = 0; i < length; i += 1) {
  45. const key = keys[i];
  46. if (!(key in b)) {
  47. return false;
  48. }
  49. if (a[key] !== b[key]) {
  50. return false;
  51. }
  52. }
  53. return true;
  54. }
  55. function upperFirst(value) {
  56. return typeof value !== "string" ? "" : value.charAt(0).toUpperCase() + value.slice(1);
  57. }
  58. function useCallbackRef(callback) {
  59. const callbackRef = React.useRef(callback);
  60. React.useEffect(() => {
  61. callbackRef.current = callback;
  62. });
  63. return React.useMemo(() => (...args) => callbackRef.current?.(...args), []);
  64. }
  65. function useDebouncedCallback(callback, delay) {
  66. const handleCallback = useCallbackRef(callback);
  67. const debounceTimerRef = React.useRef(0);
  68. React.useEffect(() => () => window.clearTimeout(debounceTimerRef.current), []);
  69. return React.useCallback(
  70. (...args) => {
  71. window.clearTimeout(debounceTimerRef.current);
  72. debounceTimerRef.current = window.setTimeout(() => handleCallback(...args), delay);
  73. },
  74. [handleCallback, delay]
  75. );
  76. }
  77. var DEFAULT_EVENTS = ["mousedown", "touchstart"];
  78. function useClickOutside(handler, events, nodes) {
  79. const ref = React.useRef(null);
  80. React.useEffect(() => {
  81. const listener = (event) => {
  82. const { target } = event ?? {};
  83. if (Array.isArray(nodes)) {
  84. const shouldIgnore = target?.hasAttribute("data-ignore-outside-clicks") || !document.body.contains(target) && target.tagName !== "HTML";
  85. const shouldTrigger = nodes.every((node) => !!node && !event.composedPath().includes(node));
  86. shouldTrigger && !shouldIgnore && handler();
  87. } else if (ref.current && !ref.current.contains(target)) {
  88. handler();
  89. }
  90. };
  91. (events || DEFAULT_EVENTS).forEach((fn) => document.addEventListener(fn, listener));
  92. return () => {
  93. (events || DEFAULT_EVENTS).forEach((fn) => document.removeEventListener(fn, listener));
  94. };
  95. }, [ref, handler, nodes]);
  96. return ref;
  97. }
  98. function useClipboard({ timeout = 2e3 } = {}) {
  99. const [error, setError] = React.useState(null);
  100. const [copied, setCopied] = React.useState(false);
  101. const [copyTimeout, setCopyTimeout] = React.useState(null);
  102. const handleCopyResult = (value) => {
  103. window.clearTimeout(copyTimeout);
  104. setCopyTimeout(window.setTimeout(() => setCopied(false), timeout));
  105. setCopied(value);
  106. };
  107. const copy = (valueToCopy) => {
  108. if ("clipboard" in navigator) {
  109. navigator.clipboard.writeText(valueToCopy).then(() => handleCopyResult(true)).catch((err) => setError(err));
  110. } else {
  111. setError(new Error("useClipboard: navigator.clipboard is not supported"));
  112. }
  113. };
  114. const reset = () => {
  115. setCopied(false);
  116. setError(null);
  117. window.clearTimeout(copyTimeout);
  118. };
  119. return { copy, reset, error, copied };
  120. }
  121. function attachMediaListener(query, callback) {
  122. try {
  123. query.addEventListener("change", callback);
  124. return () => query.removeEventListener("change", callback);
  125. } catch (e) {
  126. query.addListener(callback);
  127. return () => query.removeListener(callback);
  128. }
  129. }
  130. function getInitialValue(query, initialValue) {
  131. if (typeof window !== "undefined" && "matchMedia" in window) {
  132. return window.matchMedia(query).matches;
  133. }
  134. return false;
  135. }
  136. function useMediaQuery(query, initialValue, { getInitialValueInEffect } = {
  137. getInitialValueInEffect: true
  138. }) {
  139. const [matches, setMatches] = React.useState(
  140. getInitialValueInEffect ? initialValue : getInitialValue(query)
  141. );
  142. const queryRef = React.useRef(null);
  143. React.useEffect(() => {
  144. if ("matchMedia" in window) {
  145. queryRef.current = window.matchMedia(query);
  146. setMatches(queryRef.current.matches);
  147. return attachMediaListener(queryRef.current, (event) => setMatches(event.matches));
  148. }
  149. return void 0;
  150. }, [query]);
  151. return matches;
  152. }
  153. function useColorScheme(initialValue, options) {
  154. return useMediaQuery("(prefers-color-scheme: dark)", initialValue === "dark", options) ? "dark" : "light";
  155. }
  156. var DEFAULT_OPTIONS = {
  157. min: -Infinity,
  158. max: Infinity
  159. };
  160. function useCounter(initialValue = 0, options) {
  161. const { min, max } = { ...DEFAULT_OPTIONS, ...options };
  162. const [count, setCount] = React.useState(clamp(initialValue, min, max));
  163. const increment = () => setCount((current) => clamp(current + 1, min, max));
  164. const decrement = () => setCount((current) => clamp(current - 1, min, max));
  165. const set = (value) => setCount(clamp(value, min, max));
  166. const reset = () => setCount(clamp(initialValue, min, max));
  167. return [count, { increment, decrement, set, reset }];
  168. }
  169. function useDebouncedState(defaultValue, wait, options = { leading: false }) {
  170. const [value, setValue] = React.useState(defaultValue);
  171. const timeoutRef = React.useRef(null);
  172. const leadingRef = React.useRef(true);
  173. const clearTimeout2 = () => window.clearTimeout(timeoutRef.current);
  174. React.useEffect(() => clearTimeout2, []);
  175. const debouncedSetValue = React.useCallback(
  176. (newValue) => {
  177. clearTimeout2();
  178. if (leadingRef.current && options.leading) {
  179. setValue(newValue);
  180. } else {
  181. timeoutRef.current = window.setTimeout(() => {
  182. leadingRef.current = true;
  183. setValue(newValue);
  184. }, wait);
  185. }
  186. leadingRef.current = false;
  187. },
  188. [options.leading]
  189. );
  190. return [value, debouncedSetValue];
  191. }
  192. function useDebouncedValue(value, wait, options = { leading: false }) {
  193. const [_value, setValue] = React.useState(value);
  194. const mountedRef = React.useRef(false);
  195. const timeoutRef = React.useRef(null);
  196. const cooldownRef = React.useRef(false);
  197. const cancel = () => window.clearTimeout(timeoutRef.current);
  198. React.useEffect(() => {
  199. if (mountedRef.current) {
  200. if (!cooldownRef.current && options.leading) {
  201. cooldownRef.current = true;
  202. setValue(value);
  203. } else {
  204. cancel();
  205. timeoutRef.current = window.setTimeout(() => {
  206. cooldownRef.current = false;
  207. setValue(value);
  208. }, wait);
  209. }
  210. }
  211. }, [value, options.leading, wait]);
  212. React.useEffect(() => {
  213. mountedRef.current = true;
  214. return cancel;
  215. }, []);
  216. return [_value, cancel];
  217. }
  218. var useIsomorphicEffect = typeof document !== "undefined" ? React.useLayoutEffect : React.useEffect;
  219. function useDocumentTitle(title) {
  220. useIsomorphicEffect(() => {
  221. if (typeof title === "string" && title.trim().length > 0) {
  222. document.title = title.trim();
  223. }
  224. }, [title]);
  225. }
  226. function useDocumentVisibility() {
  227. const [documentVisibility, setDocumentVisibility] = React.useState("visible");
  228. React.useEffect(() => {
  229. const listener = () => setDocumentVisibility(document.visibilityState);
  230. document.addEventListener("visibilitychange", listener);
  231. return () => document.removeEventListener("visibilitychange", listener);
  232. }, []);
  233. return documentVisibility;
  234. }
  235. function useDidUpdate(fn, dependencies) {
  236. const mounted = React.useRef(false);
  237. React.useEffect(
  238. () => () => {
  239. mounted.current = false;
  240. },
  241. []
  242. );
  243. React.useEffect(() => {
  244. if (mounted.current) {
  245. return fn();
  246. }
  247. mounted.current = true;
  248. return void 0;
  249. }, dependencies);
  250. }
  251. function useFocusReturn({ opened, shouldReturnFocus = true }) {
  252. const lastActiveElement = React.useRef(null);
  253. const returnFocus = () => {
  254. if (lastActiveElement.current && "focus" in lastActiveElement.current && typeof lastActiveElement.current.focus === "function") {
  255. lastActiveElement.current?.focus({ preventScroll: true });
  256. }
  257. };
  258. useDidUpdate(() => {
  259. let timeout = -1;
  260. const clearFocusTimeout = (event) => {
  261. if (event.key === "Tab") {
  262. window.clearTimeout(timeout);
  263. }
  264. };
  265. document.addEventListener("keydown", clearFocusTimeout);
  266. if (opened) {
  267. lastActiveElement.current = document.activeElement;
  268. } else if (shouldReturnFocus) {
  269. timeout = window.setTimeout(returnFocus, 10);
  270. }
  271. return () => {
  272. window.clearTimeout(timeout);
  273. document.removeEventListener("keydown", clearFocusTimeout);
  274. };
  275. }, [opened, shouldReturnFocus]);
  276. return returnFocus;
  277. }
  278. var TABBABLE_NODES = /input|select|textarea|button|object/;
  279. var FOCUS_SELECTOR = "a, input, select, textarea, button, object, [tabindex]";
  280. function hidden(element) {
  281. return element.style.display === "none";
  282. }
  283. function visible(element) {
  284. const isHidden = element.getAttribute("aria-hidden") || element.getAttribute("hidden") || element.getAttribute("type") === "hidden";
  285. if (isHidden) {
  286. return false;
  287. }
  288. let parentElement = element;
  289. while (parentElement) {
  290. if (parentElement === document.body || parentElement.nodeType === 11) {
  291. break;
  292. }
  293. if (hidden(parentElement)) {
  294. return false;
  295. }
  296. parentElement = parentElement.parentNode;
  297. }
  298. return true;
  299. }
  300. function getElementTabIndex(element) {
  301. let tabIndex = element.getAttribute("tabindex");
  302. if (tabIndex === null) {
  303. tabIndex = void 0;
  304. }
  305. return parseInt(tabIndex, 10);
  306. }
  307. function focusable(element) {
  308. const nodeName = element.nodeName.toLowerCase();
  309. const isTabIndexNotNaN = !Number.isNaN(getElementTabIndex(element));
  310. const res = (
  311. TABBABLE_NODES.test(nodeName) && !element.disabled || (element instanceof HTMLAnchorElement ? element.href || isTabIndexNotNaN : isTabIndexNotNaN)
  312. );
  313. return res && visible(element);
  314. }
  315. function tabbable(element) {
  316. const tabIndex = getElementTabIndex(element);
  317. const isTabIndexNaN = Number.isNaN(tabIndex);
  318. return (isTabIndexNaN || tabIndex >= 0) && focusable(element);
  319. }
  320. function findTabbableDescendants(element) {
  321. return Array.from(element.querySelectorAll(FOCUS_SELECTOR)).filter(tabbable);
  322. }
  323. function scopeTab(node, event) {
  324. const tabbable2 = findTabbableDescendants(node);
  325. if (!tabbable2.length) {
  326. event.preventDefault();
  327. return;
  328. }
  329. const finalTabbable = tabbable2[event.shiftKey ? 0 : tabbable2.length - 1];
  330. const root = node.getRootNode();
  331. let leavingFinalTabbable = finalTabbable === root.activeElement || node === root.activeElement;
  332. const activeElement = root.activeElement;
  333. const activeElementIsRadio = activeElement.tagName === "INPUT" && activeElement.getAttribute("type") === "radio";
  334. if (activeElementIsRadio) {
  335. const activeRadioGroup = tabbable2.filter(
  336. (element) => element.getAttribute("type") === "radio" && element.getAttribute("name") === activeElement.getAttribute("name")
  337. );
  338. leavingFinalTabbable = activeRadioGroup.includes(finalTabbable);
  339. }
  340. if (!leavingFinalTabbable) {
  341. return;
  342. }
  343. event.preventDefault();
  344. const target = tabbable2[event.shiftKey ? tabbable2.length - 1 : 0];
  345. if (target) {
  346. target.focus();
  347. }
  348. }
  349. function useFocusTrap(active = true) {
  350. const ref = React.useRef(null);
  351. const focusNode = (node) => {
  352. let focusElement = node.querySelector("[data-autofocus]");
  353. if (!focusElement) {
  354. const children = Array.from(node.querySelectorAll(FOCUS_SELECTOR));
  355. focusElement = children.find(tabbable) || children.find(focusable) || null;
  356. if (!focusElement && focusable(node)) {
  357. focusElement = node;
  358. }
  359. }
  360. if (focusElement) {
  361. focusElement.focus({ preventScroll: true });
  362. } else {
  363. console.warn(
  364. "[@mantine/hooks/use-focus-trap] Failed to find focusable element within provided node",
  365. node
  366. );
  367. }
  368. };
  369. const setRef = React.useCallback(
  370. (node) => {
  371. if (!active) {
  372. return;
  373. }
  374. if (node === null) {
  375. return;
  376. }
  377. if (ref.current === node) {
  378. return;
  379. }
  380. if (node) {
  381. setTimeout(() => {
  382. if (node.getRootNode()) {
  383. focusNode(node);
  384. } else {
  385. console.warn("[@mantine/hooks/use-focus-trap] Ref node is not part of the dom", node);
  386. }
  387. });
  388. ref.current = node;
  389. } else {
  390. ref.current = null;
  391. }
  392. },
  393. [active]
  394. );
  395. React.useEffect(() => {
  396. if (!active) {
  397. return void 0;
  398. }
  399. ref.current && setTimeout(() => focusNode(ref.current));
  400. const handleKeyDown = (event) => {
  401. if (event.key === "Tab" && ref.current) {
  402. scopeTab(ref.current, event);
  403. }
  404. };
  405. document.addEventListener("keydown", handleKeyDown);
  406. return () => document.removeEventListener("keydown", handleKeyDown);
  407. }, [active]);
  408. return setRef;
  409. }
  410. var reducer = (value) => (value + 1) % 1e6;
  411. function useForceUpdate() {
  412. const [, update] = React.useReducer(reducer, 0);
  413. return update;
  414. }
  415. var __useId = React["useId".toString()] || (() => void 0);
  416. function useReactId() {
  417. const id = __useId();
  418. return id ? `mantine-${id.replace(/:/g, "")}` : "";
  419. }
  420. function useId(staticId) {
  421. const reactId = useReactId();
  422. const [uuid, setUuid] = React.useState(reactId);
  423. useIsomorphicEffect(() => {
  424. setUuid(randomId());
  425. }, []);
  426. if (typeof staticId === "string") {
  427. return staticId;
  428. }
  429. if (typeof window === "undefined") {
  430. return reactId;
  431. }
  432. return uuid;
  433. }
  434. var DEFAULT_EVENTS2 = [
  435. "keypress",
  436. "mousemove",
  437. "touchmove",
  438. "click",
  439. "scroll"
  440. ];
  441. var DEFAULT_OPTIONS2 = {
  442. events: DEFAULT_EVENTS2,
  443. initialState: true
  444. };
  445. function useIdle(timeout, options) {
  446. const { events, initialState } = { ...DEFAULT_OPTIONS2, ...options };
  447. const [idle, setIdle] = React.useState(initialState);
  448. const timer = React.useRef(-1);
  449. React.useEffect(() => {
  450. const handleEvents = () => {
  451. setIdle(false);
  452. if (timer.current) {
  453. window.clearTimeout(timer.current);
  454. }
  455. timer.current = window.setTimeout(() => {
  456. setIdle(true);
  457. }, timeout);
  458. };
  459. events.forEach((event) => document.addEventListener(event, handleEvents));
  460. timer.current = window.setTimeout(() => {
  461. setIdle(true);
  462. }, timeout);
  463. return () => {
  464. events.forEach((event) => document.removeEventListener(event, handleEvents));
  465. };
  466. }, [timeout]);
  467. return idle;
  468. }
  469. function useInterval(fn, interval, { autoInvoke = false } = {}) {
  470. const [active, setActive] = React.useState(false);
  471. const intervalRef = React.useRef(null);
  472. const fnRef = React.useRef(null);
  473. const start = () => {
  474. setActive((old) => {
  475. if (!old && (!intervalRef.current || intervalRef.current === -1)) {
  476. intervalRef.current = window.setInterval(fnRef.current, interval);
  477. }
  478. return true;
  479. });
  480. };
  481. const stop = () => {
  482. setActive(false);
  483. window.clearInterval(intervalRef.current || -1);
  484. intervalRef.current = -1;
  485. };
  486. const toggle = () => {
  487. if (active) {
  488. stop();
  489. } else {
  490. start();
  491. }
  492. };
  493. React.useEffect(() => {
  494. fnRef.current = fn;
  495. active && start();
  496. return stop;
  497. }, [fn, active, interval]);
  498. React.useEffect(() => {
  499. if (autoInvoke) {
  500. start();
  501. }
  502. }, []);
  503. return { start, stop, toggle, active };
  504. }
  505. function useListState(initialValue = []) {
  506. const [state, setState] = React.useState(initialValue);
  507. const append = (...items) => setState((current) => [...current, ...items]);
  508. const prepend = (...items) => setState((current) => [...items, ...current]);
  509. const insert = (index, ...items) => setState((current) => [...current.slice(0, index), ...items, ...current.slice(index)]);
  510. const apply = (fn) => setState((current) => current.map((item, index) => fn(item, index)));
  511. const remove = (...indices) => setState((current) => current.filter((_, index) => !indices.includes(index)));
  512. const pop = () => setState((current) => {
  513. const cloned = [...current];
  514. cloned.pop();
  515. return cloned;
  516. });
  517. const shift = () => setState((current) => {
  518. const cloned = [...current];
  519. cloned.shift();
  520. return cloned;
  521. });
  522. const reorder = ({ from, to }) => setState((current) => {
  523. const cloned = [...current];
  524. const item = current[from];
  525. cloned.splice(from, 1);
  526. cloned.splice(to, 0, item);
  527. return cloned;
  528. });
  529. const swap = ({ from, to }) => setState((current) => {
  530. const cloned = [...current];
  531. const fromItem = cloned[from];
  532. const toItem = cloned[to];
  533. cloned.splice(to, 1, fromItem);
  534. cloned.splice(from, 1, toItem);
  535. return cloned;
  536. });
  537. const setItem = (index, item) => setState((current) => {
  538. const cloned = [...current];
  539. cloned[index] = item;
  540. return cloned;
  541. });
  542. const setItemProp = (index, prop, value) => setState((current) => {
  543. const cloned = [...current];
  544. cloned[index] = { ...cloned[index], [prop]: value };
  545. return cloned;
  546. });
  547. const applyWhere = (condition, fn) => setState(
  548. (current) => current.map((item, index) => condition(item, index) ? fn(item, index) : item)
  549. );
  550. const filter = (fn) => {
  551. setState((current) => current.filter(fn));
  552. };
  553. return [
  554. state,
  555. {
  556. setState,
  557. append,
  558. prepend,
  559. insert,
  560. pop,
  561. shift,
  562. apply,
  563. applyWhere,
  564. remove,
  565. reorder,
  566. swap,
  567. setItem,
  568. setItemProp,
  569. filter
  570. }
  571. ];
  572. }
  573. function useWindowEvent(type, listener, options) {
  574. React.useEffect(() => {
  575. window.addEventListener(type, listener, options);
  576. return () => window.removeEventListener(type, listener, options);
  577. }, [type, listener]);
  578. }
  579. function serializeJSON(value, hookName = "use-local-storage") {
  580. try {
  581. return JSON.stringify(value);
  582. } catch (error) {
  583. throw new Error(`@mantine/hooks ${hookName}: Failed to serialize the value`);
  584. }
  585. }
  586. function deserializeJSON(value) {
  587. try {
  588. return value && JSON.parse(value);
  589. } catch {
  590. return value;
  591. }
  592. }
  593. function createStorageHandler(type) {
  594. const getItem = (key) => {
  595. try {
  596. return window[type].getItem(key);
  597. } catch (error) {
  598. console.warn("use-local-storage: Failed to get value from storage, localStorage is blocked");
  599. return null;
  600. }
  601. };
  602. const setItem = (key, value) => {
  603. try {
  604. window[type].setItem(key, value);
  605. } catch (error) {
  606. console.warn("use-local-storage: Failed to set value to storage, localStorage is blocked");
  607. }
  608. };
  609. const removeItem = (key) => {
  610. try {
  611. window[type].removeItem(key);
  612. } catch (error) {
  613. console.warn(
  614. "use-local-storage: Failed to remove value from storage, localStorage is blocked"
  615. );
  616. }
  617. };
  618. return { getItem, setItem, removeItem };
  619. }
  620. function createStorage(type, hookName) {
  621. const eventName = type === "localStorage" ? "mantine-local-storage" : "mantine-session-storage";
  622. const { getItem, setItem, removeItem } = createStorageHandler(type);
  623. return function useStorage({
  624. key,
  625. defaultValue,
  626. getInitialValueInEffect = true,
  627. deserialize = deserializeJSON,
  628. serialize = (value) => serializeJSON(value, hookName)
  629. }) {
  630. const readStorageValue = React.useCallback(
  631. (skipStorage) => {
  632. let storageBlockedOrSkipped;
  633. try {
  634. storageBlockedOrSkipped = typeof window === "undefined" || !(type in window) || window[type] === null || !!skipStorage;
  635. } catch (_e) {
  636. storageBlockedOrSkipped = true;
  637. }
  638. if (storageBlockedOrSkipped) {
  639. return defaultValue;
  640. }
  641. const storageValue = getItem(key);
  642. return storageValue !== null ? deserialize(storageValue) : defaultValue;
  643. },
  644. [key, defaultValue]
  645. );
  646. const [value, setValue] = React.useState(readStorageValue(getInitialValueInEffect));
  647. const setStorageValue = React.useCallback(
  648. (val) => {
  649. if (val instanceof Function) {
  650. setValue((current) => {
  651. const result = val(current);
  652. setItem(key, serialize(result));
  653. window.dispatchEvent(
  654. new CustomEvent(eventName, { detail: { key, value: val(current) } })
  655. );
  656. return result;
  657. });
  658. } else {
  659. setItem(key, serialize(val));
  660. window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: val } }));
  661. setValue(val);
  662. }
  663. },
  664. [key]
  665. );
  666. const removeStorageValue = React.useCallback(() => {
  667. removeItem(key);
  668. window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: defaultValue } }));
  669. }, []);
  670. useWindowEvent("storage", (event) => {
  671. if (event.storageArea === window[type] && event.key === key) {
  672. setValue(deserialize(event.newValue ?? void 0));
  673. }
  674. });
  675. useWindowEvent(eventName, (event) => {
  676. if (event.detail.key === key) {
  677. setValue(event.detail.value);
  678. }
  679. });
  680. React.useEffect(() => {
  681. if (defaultValue !== void 0 && value === void 0) {
  682. setStorageValue(defaultValue);
  683. }
  684. }, [defaultValue, value, setStorageValue]);
  685. React.useEffect(() => {
  686. const val = readStorageValue();
  687. val !== void 0 && setStorageValue(val);
  688. }, [key]);
  689. return [value === void 0 ? defaultValue : value, setStorageValue, removeStorageValue];
  690. };
  691. }
  692. function readValue(type) {
  693. const { getItem } = createStorageHandler(type);
  694. return function read({
  695. key,
  696. defaultValue,
  697. deserialize = deserializeJSON
  698. }) {
  699. let storageBlockedOrSkipped;
  700. try {
  701. storageBlockedOrSkipped = typeof window === "undefined" || !(type in window) || window[type] === null;
  702. } catch (_e) {
  703. storageBlockedOrSkipped = true;
  704. }
  705. if (storageBlockedOrSkipped) {
  706. return defaultValue;
  707. }
  708. const storageValue = getItem(key);
  709. return storageValue !== null ? deserialize(storageValue) : defaultValue;
  710. };
  711. }
  712. function useLocalStorage(props) {
  713. return createStorage("localStorage", "use-local-storage")(props);
  714. }
  715. var readLocalStorageValue = readValue("localStorage");
  716. function useSessionStorage(props) {
  717. return createStorage("sessionStorage", "use-session-storage")(props);
  718. }
  719. var readSessionStorageValue = readValue("sessionStorage");
  720. function assignRef(ref, value) {
  721. if (typeof ref === "function") {
  722. ref(value);
  723. } else if (typeof ref === "object" && ref !== null && "current" in ref) {
  724. ref.current = value;
  725. }
  726. }
  727. function mergeRefs(...refs) {
  728. return (node) => {
  729. refs.forEach((ref) => assignRef(ref, node));
  730. };
  731. }
  732. function useMergedRef(...refs) {
  733. return React.useCallback(mergeRefs(...refs), refs);
  734. }
  735. function useMouse(options = { resetOnExit: false }) {
  736. const [position, setPosition] = React.useState({ x: 0, y: 0 });
  737. const ref = React.useRef(null);
  738. const setMousePosition = (event) => {
  739. if (ref.current) {
  740. const rect = event.currentTarget.getBoundingClientRect();
  741. const x = Math.max(
  742. 0,
  743. Math.round(event.pageX - rect.left - (window.pageXOffset || window.scrollX))
  744. );
  745. const y = Math.max(
  746. 0,
  747. Math.round(event.pageY - rect.top - (window.pageYOffset || window.scrollY))
  748. );
  749. setPosition({ x, y });
  750. } else {
  751. setPosition({ x: event.clientX, y: event.clientY });
  752. }
  753. };
  754. const resetMousePosition = () => setPosition({ x: 0, y: 0 });
  755. React.useEffect(() => {
  756. const element = ref?.current ? ref.current : document;
  757. element.addEventListener("mousemove", setMousePosition);
  758. if (options.resetOnExit) {
  759. element.addEventListener("mouseleave", resetMousePosition);
  760. }
  761. return () => {
  762. element.removeEventListener("mousemove", setMousePosition);
  763. if (options.resetOnExit) {
  764. element.removeEventListener("mouseleave", resetMousePosition);
  765. }
  766. };
  767. }, [ref.current]);
  768. return { ref, ...position };
  769. }
  770. function clampUseMovePosition(position) {
  771. return {
  772. x: clamp(position.x, 0, 1),
  773. y: clamp(position.y, 0, 1)
  774. };
  775. }
  776. function useMove(onChange, handlers, dir = "ltr") {
  777. const ref = React.useRef(null);
  778. const mounted = React.useRef(false);
  779. const isSliding = React.useRef(false);
  780. const frame = React.useRef(0);
  781. const [active, setActive] = React.useState(false);
  782. React.useEffect(() => {
  783. mounted.current = true;
  784. }, []);
  785. React.useEffect(() => {
  786. const onScrub = ({ x, y }) => {
  787. cancelAnimationFrame(frame.current);
  788. frame.current = requestAnimationFrame(() => {
  789. if (mounted.current && ref.current) {
  790. ref.current.style.userSelect = "none";
  791. const rect = ref.current.getBoundingClientRect();
  792. if (rect.width && rect.height) {
  793. const _x = clamp((x - rect.left) / rect.width, 0, 1);
  794. onChange({
  795. x: dir === "ltr" ? _x : 1 - _x,
  796. y: clamp((y - rect.top) / rect.height, 0, 1)
  797. });
  798. }
  799. }
  800. });
  801. };
  802. const bindEvents = () => {
  803. document.addEventListener("mousemove", onMouseMove);
  804. document.addEventListener("mouseup", stopScrubbing);
  805. document.addEventListener("touchmove", onTouchMove);
  806. document.addEventListener("touchend", stopScrubbing);
  807. };
  808. const unbindEvents = () => {
  809. document.removeEventListener("mousemove", onMouseMove);
  810. document.removeEventListener("mouseup", stopScrubbing);
  811. document.removeEventListener("touchmove", onTouchMove);
  812. document.removeEventListener("touchend", stopScrubbing);
  813. };
  814. const startScrubbing = () => {
  815. if (!isSliding.current && mounted.current) {
  816. isSliding.current = true;
  817. typeof handlers?.onScrubStart === "function" && handlers.onScrubStart();
  818. setActive(true);
  819. bindEvents();
  820. }
  821. };
  822. const stopScrubbing = () => {
  823. if (isSliding.current && mounted.current) {
  824. isSliding.current = false;
  825. setActive(false);
  826. unbindEvents();
  827. setTimeout(() => {
  828. typeof handlers?.onScrubEnd === "function" && handlers.onScrubEnd();
  829. }, 0);
  830. }
  831. };
  832. const onMouseDown = (event) => {
  833. startScrubbing();
  834. event.preventDefault();
  835. onMouseMove(event);
  836. };
  837. const onMouseMove = (event) => onScrub({ x: event.clientX, y: event.clientY });
  838. const onTouchStart = (event) => {
  839. if (event.cancelable) {
  840. event.preventDefault();
  841. }
  842. startScrubbing();
  843. onTouchMove(event);
  844. };
  845. const onTouchMove = (event) => {
  846. if (event.cancelable) {
  847. event.preventDefault();
  848. }
  849. onScrub({ x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY });
  850. };
  851. ref.current?.addEventListener("mousedown", onMouseDown);
  852. ref.current?.addEventListener("touchstart", onTouchStart, { passive: false });
  853. return () => {
  854. if (ref.current) {
  855. ref.current.removeEventListener("mousedown", onMouseDown);
  856. ref.current.removeEventListener("touchstart", onTouchStart);
  857. }
  858. };
  859. }, [dir, onChange]);
  860. return { ref, active };
  861. }
  862. function useUncontrolled({
  863. value,
  864. defaultValue,
  865. finalValue,
  866. onChange = () => {
  867. }
  868. }) {
  869. const [uncontrolledValue, setUncontrolledValue] = React.useState(
  870. defaultValue !== void 0 ? defaultValue : finalValue
  871. );
  872. const handleUncontrolledChange = (val, ...payload) => {
  873. setUncontrolledValue(val);
  874. onChange?.(val, ...payload);
  875. };
  876. if (value !== void 0) {
  877. return [value, onChange, true];
  878. }
  879. return [uncontrolledValue, handleUncontrolledChange, false];
  880. }
  881. function range2(start, end) {
  882. const length = end - start + 1;
  883. return Array.from({ length }, (_, index) => index + start);
  884. }
  885. var DOTS = "dots";
  886. function usePagination({
  887. total,
  888. siblings = 1,
  889. boundaries = 1,
  890. page,
  891. initialPage = 1,
  892. onChange
  893. }) {
  894. const _total = Math.max(Math.trunc(total), 0);
  895. const [activePage, setActivePage] = useUncontrolled({
  896. value: page,
  897. onChange,
  898. defaultValue: initialPage,
  899. finalValue: initialPage
  900. });
  901. const setPage = (pageNumber) => {
  902. if (pageNumber <= 0) {
  903. setActivePage(1);
  904. } else if (pageNumber > _total) {
  905. setActivePage(_total);
  906. } else {
  907. setActivePage(pageNumber);
  908. }
  909. };
  910. const next = () => setPage(activePage + 1);
  911. const previous = () => setPage(activePage - 1);
  912. const first = () => setPage(1);
  913. const last = () => setPage(_total);
  914. const paginationRange = React.useMemo(() => {
  915. const totalPageNumbers = siblings * 2 + 3 + boundaries * 2;
  916. if (totalPageNumbers >= _total) {
  917. return range2(1, _total);
  918. }
  919. const leftSiblingIndex = Math.max(activePage - siblings, boundaries);
  920. const rightSiblingIndex = Math.min(activePage + siblings, _total - boundaries);
  921. const shouldShowLeftDots = leftSiblingIndex > boundaries + 2;
  922. const shouldShowRightDots = rightSiblingIndex < _total - (boundaries + 1);
  923. if (!shouldShowLeftDots && shouldShowRightDots) {
  924. const leftItemCount = siblings * 2 + boundaries + 2;
  925. return [...range2(1, leftItemCount), DOTS, ...range2(_total - (boundaries - 1), _total)];
  926. }
  927. if (shouldShowLeftDots && !shouldShowRightDots) {
  928. const rightItemCount = boundaries + 1 + 2 * siblings;
  929. return [...range2(1, boundaries), DOTS, ...range2(_total - rightItemCount, _total)];
  930. }
  931. return [
  932. ...range2(1, boundaries),
  933. DOTS,
  934. ...range2(leftSiblingIndex, rightSiblingIndex),
  935. DOTS,
  936. ...range2(_total - boundaries + 1, _total)
  937. ];
  938. }, [_total, siblings, activePage]);
  939. return {
  940. range: paginationRange,
  941. active: activePage,
  942. setPage,
  943. next,
  944. previous,
  945. first,
  946. last
  947. };
  948. }
  949. function useQueue({ initialValues = [], limit }) {
  950. const [state, setState] = React.useState({
  951. state: initialValues.slice(0, limit),
  952. queue: initialValues.slice(limit)
  953. });
  954. const add = (...items) => setState((current) => {
  955. const results = [...current.state, ...current.queue, ...items];
  956. return {
  957. state: results.slice(0, limit),
  958. queue: results.slice(limit)
  959. };
  960. });
  961. const update = (fn) => setState((current) => {
  962. const results = fn([...current.state, ...current.queue]);
  963. return {
  964. state: results.slice(0, limit),
  965. queue: results.slice(limit)
  966. };
  967. });
  968. const cleanQueue = () => setState((current) => ({ state: current.state, queue: [] }));
  969. return {
  970. state: state.state,
  971. queue: state.queue,
  972. add,
  973. update,
  974. cleanQueue
  975. };
  976. }
  977. function usePageLeave(onPageLeave) {
  978. React.useEffect(() => {
  979. document.documentElement.addEventListener("mouseleave", onPageLeave);
  980. return () => document.documentElement.removeEventListener("mouseleave", onPageLeave);
  981. }, []);
  982. }
  983. function useReducedMotion(initialValue, options) {
  984. return useMediaQuery("(prefers-reduced-motion: reduce)", initialValue, options);
  985. }
  986. var easeInOutQuad = (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
  987. var getRelativePosition = ({
  988. axis,
  989. target,
  990. parent,
  991. alignment,
  992. offset,
  993. isList
  994. }) => {
  995. if (!target || !parent && typeof document === "undefined") {
  996. return 0;
  997. }
  998. const isCustomParent = !!parent;
  999. const parentElement = parent || document.body;
  1000. const parentPosition = parentElement.getBoundingClientRect();
  1001. const targetPosition = target.getBoundingClientRect();
  1002. const getDiff = (property) => targetPosition[property] - parentPosition[property];
  1003. if (axis === "y") {
  1004. const diff = getDiff("top");
  1005. if (diff === 0) {
  1006. return 0;
  1007. }
  1008. if (alignment === "start") {
  1009. const distance = diff - offset;
  1010. const shouldScroll = distance <= targetPosition.height * (isList ? 0 : 1) || !isList;
  1011. return shouldScroll ? distance : 0;
  1012. }
  1013. const parentHeight = isCustomParent ? parentPosition.height : window.innerHeight;
  1014. if (alignment === "end") {
  1015. const distance = diff + offset - parentHeight + targetPosition.height;
  1016. const shouldScroll = distance >= -targetPosition.height * (isList ? 0 : 1) || !isList;
  1017. return shouldScroll ? distance : 0;
  1018. }
  1019. if (alignment === "center") {
  1020. return diff - parentHeight / 2 + targetPosition.height / 2;
  1021. }
  1022. return 0;
  1023. }
  1024. if (axis === "x") {
  1025. const diff = getDiff("left");
  1026. if (diff === 0) {
  1027. return 0;
  1028. }
  1029. if (alignment === "start") {
  1030. const distance = diff - offset;
  1031. const shouldScroll = distance <= targetPosition.width || !isList;
  1032. return shouldScroll ? distance : 0;
  1033. }
  1034. const parentWidth = isCustomParent ? parentPosition.width : window.innerWidth;
  1035. if (alignment === "end") {
  1036. const distance = diff + offset - parentWidth + targetPosition.width;
  1037. const shouldScroll = distance >= -targetPosition.width || !isList;
  1038. return shouldScroll ? distance : 0;
  1039. }
  1040. if (alignment === "center") {
  1041. return diff - parentWidth / 2 + targetPosition.width / 2;
  1042. }
  1043. return 0;
  1044. }
  1045. return 0;
  1046. };
  1047. var getScrollStart = ({ axis, parent }) => {
  1048. if (!parent && typeof document === "undefined") {
  1049. return 0;
  1050. }
  1051. const method = axis === "y" ? "scrollTop" : "scrollLeft";
  1052. if (parent) {
  1053. return parent[method];
  1054. }
  1055. const { body, documentElement } = document;
  1056. return body[method] + documentElement[method];
  1057. };
  1058. var setScrollParam = ({ axis, parent, distance }) => {
  1059. if (!parent && typeof document === "undefined") {
  1060. return;
  1061. }
  1062. const method = axis === "y" ? "scrollTop" : "scrollLeft";
  1063. if (parent) {
  1064. parent[method] = distance;
  1065. } else {
  1066. const { body, documentElement } = document;
  1067. body[method] = distance;
  1068. documentElement[method] = distance;
  1069. }
  1070. };
  1071. function useScrollIntoView({
  1072. duration = 1250,
  1073. axis = "y",
  1074. onScrollFinish,
  1075. easing = easeInOutQuad,
  1076. offset = 0,
  1077. cancelable = true,
  1078. isList = false
  1079. } = {}) {
  1080. const frameID = React.useRef(0);
  1081. const startTime = React.useRef(0);
  1082. const shouldStop = React.useRef(false);
  1083. const scrollableRef = React.useRef(null);
  1084. const targetRef = React.useRef(null);
  1085. const reducedMotion = useReducedMotion();
  1086. const cancel = () => {
  1087. if (frameID.current) {
  1088. cancelAnimationFrame(frameID.current);
  1089. }
  1090. };
  1091. const scrollIntoView = React.useCallback(
  1092. ({ alignment = "start" } = {}) => {
  1093. shouldStop.current = false;
  1094. if (frameID.current) {
  1095. cancel();
  1096. }
  1097. const start = getScrollStart({ parent: scrollableRef.current, axis }) ?? 0;
  1098. const change = getRelativePosition({
  1099. parent: scrollableRef.current,
  1100. target: targetRef.current,
  1101. axis,
  1102. alignment,
  1103. offset,
  1104. isList
  1105. }) - (scrollableRef.current ? 0 : start);
  1106. function animateScroll() {
  1107. if (startTime.current === 0) {
  1108. startTime.current = performance.now();
  1109. }
  1110. const now = performance.now();
  1111. const elapsed = now - startTime.current;
  1112. const t = reducedMotion || duration === 0 ? 1 : elapsed / duration;
  1113. const distance = start + change * easing(t);
  1114. setScrollParam({
  1115. parent: scrollableRef.current,
  1116. axis,
  1117. distance
  1118. });
  1119. if (!shouldStop.current && t < 1) {
  1120. frameID.current = requestAnimationFrame(animateScroll);
  1121. } else {
  1122. typeof onScrollFinish === "function" && onScrollFinish();
  1123. startTime.current = 0;
  1124. frameID.current = 0;
  1125. cancel();
  1126. }
  1127. }
  1128. animateScroll();
  1129. },
  1130. [axis, duration, easing, isList, offset, onScrollFinish, reducedMotion]
  1131. );
  1132. const handleStop = () => {
  1133. if (cancelable) {
  1134. shouldStop.current = true;
  1135. }
  1136. };
  1137. useWindowEvent("wheel", handleStop, {
  1138. passive: true
  1139. });
  1140. useWindowEvent("touchmove", handleStop, {
  1141. passive: true
  1142. });
  1143. React.useEffect(() => cancel, []);
  1144. return {
  1145. scrollableRef,
  1146. targetRef,
  1147. scrollIntoView,
  1148. cancel
  1149. };
  1150. }
  1151. var defaultState = {
  1152. x: 0,
  1153. y: 0,
  1154. width: 0,
  1155. height: 0,
  1156. top: 0,
  1157. left: 0,
  1158. bottom: 0,
  1159. right: 0
  1160. };
  1161. function useResizeObserver(options) {
  1162. const frameID = React.useRef(0);
  1163. const ref = React.useRef(null);
  1164. const [rect, setRect] = React.useState(defaultState);
  1165. const observer = React.useMemo(
  1166. () => typeof window !== "undefined" ? new ResizeObserver((entries) => {
  1167. const entry = entries[0];
  1168. if (entry) {
  1169. cancelAnimationFrame(frameID.current);
  1170. frameID.current = requestAnimationFrame(() => {
  1171. if (ref.current) {
  1172. setRect(entry.contentRect);
  1173. }
  1174. });
  1175. }
  1176. }) : null,
  1177. []
  1178. );
  1179. React.useEffect(() => {
  1180. if (ref.current) {
  1181. observer?.observe(ref.current, options);
  1182. }
  1183. return () => {
  1184. observer?.disconnect();
  1185. if (frameID.current) {
  1186. cancelAnimationFrame(frameID.current);
  1187. }
  1188. };
  1189. }, [ref.current]);
  1190. return [ref, rect];
  1191. }
  1192. function useElementSize(options) {
  1193. const [ref, { width, height }] = useResizeObserver(options);
  1194. return { ref, width, height };
  1195. }
  1196. function shallowCompare(prevValue, currValue) {
  1197. if (!prevValue || !currValue) {
  1198. return false;
  1199. }
  1200. if (prevValue === currValue) {
  1201. return true;
  1202. }
  1203. if (prevValue.length !== currValue.length) {
  1204. return false;
  1205. }
  1206. for (let i = 0; i < prevValue.length; i += 1) {
  1207. if (!shallowEqual(prevValue[i], currValue[i])) {
  1208. return false;
  1209. }
  1210. }
  1211. return true;
  1212. }
  1213. function useShallowCompare(dependencies) {
  1214. const ref = React.useRef([]);
  1215. const updateRef = React.useRef(0);
  1216. if (!shallowCompare(ref.current, dependencies)) {
  1217. ref.current = dependencies;
  1218. updateRef.current += 1;
  1219. }
  1220. return [updateRef.current];
  1221. }
  1222. function useShallowEffect(cb, dependencies) {
  1223. React.useEffect(cb, useShallowCompare(dependencies));
  1224. }
  1225. function useToggle(options = [false, true]) {
  1226. const [[option], toggle] = React.useReducer((state, action) => {
  1227. const value = action instanceof Function ? action(state[0]) : action;
  1228. const index = Math.abs(state.indexOf(value));
  1229. return state.slice(index).concat(state.slice(0, index));
  1230. }, options);
  1231. return [option, toggle];
  1232. }
  1233. var eventListerOptions = {
  1234. passive: true
  1235. };
  1236. function useViewportSize() {
  1237. const [windowSize, setWindowSize] = React.useState({
  1238. width: 0,
  1239. height: 0
  1240. });
  1241. const setSize = React.useCallback(() => {
  1242. setWindowSize({ width: window.innerWidth || 0, height: window.innerHeight || 0 });
  1243. }, []);
  1244. useWindowEvent("resize", setSize, eventListerOptions);
  1245. useWindowEvent("orientationchange", setSize, eventListerOptions);
  1246. React.useEffect(setSize, []);
  1247. return windowSize;
  1248. }
  1249. function getScrollPosition() {
  1250. return typeof window !== "undefined" ? { x: window.pageXOffset, y: window.pageYOffset } : { x: 0, y: 0 };
  1251. }
  1252. function scrollTo({ x, y }) {
  1253. if (typeof window !== "undefined") {
  1254. const scrollOptions = { behavior: "smooth" };
  1255. if (typeof x === "number") {
  1256. scrollOptions.left = x;
  1257. }
  1258. if (typeof y === "number") {
  1259. scrollOptions.top = y;
  1260. }
  1261. window.scrollTo(scrollOptions);
  1262. }
  1263. }
  1264. function useWindowScroll() {
  1265. const [position, setPosition] = React.useState({ x: 0, y: 0 });
  1266. useWindowEvent("scroll", () => setPosition(getScrollPosition()));
  1267. useWindowEvent("resize", () => setPosition(getScrollPosition()));
  1268. React.useEffect(() => {
  1269. setPosition(getScrollPosition());
  1270. }, []);
  1271. return [position, scrollTo];
  1272. }
  1273. function useIntersection(options) {
  1274. const [entry, setEntry] = React.useState(null);
  1275. const observer = React.useRef(null);
  1276. const ref = React.useCallback(
  1277. (element) => {
  1278. if (observer.current) {
  1279. observer.current.disconnect();
  1280. observer.current = null;
  1281. }
  1282. if (element === null) {
  1283. setEntry(null);
  1284. return;
  1285. }
  1286. observer.current = new IntersectionObserver(([_entry]) => {
  1287. setEntry(_entry);
  1288. }, options);
  1289. observer.current.observe(element);
  1290. },
  1291. [options?.rootMargin, options?.root, options?.threshold]
  1292. );
  1293. return { ref, entry };
  1294. }
  1295. function useHash({ getInitialValueInEffect = true } = {}) {
  1296. const [hash, setHash] = React.useState(
  1297. getInitialValueInEffect ? "" : window.location.hash || ""
  1298. );
  1299. const setHashHandler = (value) => {
  1300. const valueWithHash = value.startsWith("#") ? value : `#${value}`;
  1301. window.location.hash = valueWithHash;
  1302. setHash(valueWithHash);
  1303. };
  1304. useWindowEvent("hashchange", () => {
  1305. const newHash = window.location.hash;
  1306. if (hash !== newHash) {
  1307. setHash(newHash);
  1308. }
  1309. });
  1310. React.useEffect(() => {
  1311. if (getInitialValueInEffect) {
  1312. setHash(window.location.hash);
  1313. }
  1314. }, []);
  1315. return [hash, setHashHandler];
  1316. }
  1317. function parseHotkey(hotkey) {
  1318. const keys = hotkey.toLowerCase().split("+").map((part) => part.trim());
  1319. const modifiers = {
  1320. alt: keys.includes("alt"),
  1321. ctrl: keys.includes("ctrl"),
  1322. meta: keys.includes("meta"),
  1323. mod: keys.includes("mod"),
  1324. shift: keys.includes("shift"),
  1325. plus: keys.includes("[plus]")
  1326. };
  1327. const reservedKeys = ["alt", "ctrl", "meta", "shift", "mod"];
  1328. const freeKey = keys.find((key) => !reservedKeys.includes(key));
  1329. return {
  1330. ...modifiers,
  1331. key: freeKey === "[plus]" ? "+" : freeKey
  1332. };
  1333. }
  1334. function isExactHotkey(hotkey, event) {
  1335. const { alt, ctrl, meta, mod, shift, key } = hotkey;
  1336. const { altKey, ctrlKey, metaKey, shiftKey, key: pressedKey } = event;
  1337. if (alt !== altKey) {
  1338. return false;
  1339. }
  1340. if (mod) {
  1341. if (!ctrlKey && !metaKey) {
  1342. return false;
  1343. }
  1344. } else {
  1345. if (ctrl !== ctrlKey) {
  1346. return false;
  1347. }
  1348. if (meta !== metaKey) {
  1349. return false;
  1350. }
  1351. }
  1352. if (shift !== shiftKey) {
  1353. return false;
  1354. }
  1355. if (key && (pressedKey.toLowerCase() === key.toLowerCase() || event.code.replace("Key", "").toLowerCase() === key.toLowerCase())) {
  1356. return true;
  1357. }
  1358. return false;
  1359. }
  1360. function getHotkeyMatcher(hotkey) {
  1361. return (event) => isExactHotkey(parseHotkey(hotkey), event);
  1362. }
  1363. function getHotkeyHandler(hotkeys) {
  1364. return (event) => {
  1365. const _event = "nativeEvent" in event ? event.nativeEvent : event;
  1366. hotkeys.forEach(([hotkey, handler, options = { preventDefault: true }]) => {
  1367. if (getHotkeyMatcher(hotkey)(_event)) {
  1368. if (options.preventDefault) {
  1369. event.preventDefault();
  1370. }
  1371. handler(_event);
  1372. }
  1373. });
  1374. };
  1375. }
  1376. function shouldFireEvent(event, tagsToIgnore, triggerOnContentEditable = false) {
  1377. if (event.target instanceof HTMLElement) {
  1378. if (triggerOnContentEditable) {
  1379. return !tagsToIgnore.includes(event.target.tagName);
  1380. }
  1381. return !event.target.isContentEditable && !tagsToIgnore.includes(event.target.tagName);
  1382. }
  1383. return true;
  1384. }
  1385. function useHotkeys(hotkeys, tagsToIgnore = ["INPUT", "TEXTAREA", "SELECT"], triggerOnContentEditable = false) {
  1386. React.useEffect(() => {
  1387. const keydownListener = (event) => {
  1388. hotkeys.forEach(([hotkey, handler, options = { preventDefault: true }]) => {
  1389. if (getHotkeyMatcher(hotkey)(event) && shouldFireEvent(event, tagsToIgnore, triggerOnContentEditable)) {
  1390. if (options.preventDefault) {
  1391. event.preventDefault();
  1392. }
  1393. handler(event);
  1394. }
  1395. });
  1396. };
  1397. document.documentElement.addEventListener("keydown", keydownListener);
  1398. return () => document.documentElement.removeEventListener("keydown", keydownListener);
  1399. }, [hotkeys]);
  1400. }
  1401. function getFullscreenElement() {
  1402. const _document = window.document;
  1403. const fullscreenElement = _document.fullscreenElement || _document.webkitFullscreenElement || _document.mozFullScreenElement || _document.msFullscreenElement;
  1404. return fullscreenElement;
  1405. }
  1406. function exitFullscreen() {
  1407. const _document = window.document;
  1408. if (typeof _document.exitFullscreen === "function") {
  1409. return _document.exitFullscreen();
  1410. }
  1411. if (typeof _document.msExitFullscreen === "function") {
  1412. return _document.msExitFullscreen();
  1413. }
  1414. if (typeof _document.webkitExitFullscreen === "function") {
  1415. return _document.webkitExitFullscreen();
  1416. }
  1417. if (typeof _document.mozCancelFullScreen === "function") {
  1418. return _document.mozCancelFullScreen();
  1419. }
  1420. return null;
  1421. }
  1422. function enterFullScreen(element) {
  1423. const _element = element;
  1424. return _element.requestFullscreen?.() || _element.msRequestFullscreen?.() || _element.webkitEnterFullscreen?.() || _element.webkitRequestFullscreen?.() || _element.mozRequestFullscreen?.();
  1425. }
  1426. var prefixes = ["", "webkit", "moz", "ms"];
  1427. function addEvents(element, {
  1428. onFullScreen,
  1429. onError
  1430. }) {
  1431. prefixes.forEach((prefix) => {
  1432. element.addEventListener(`${prefix}fullscreenchange`, onFullScreen);
  1433. element.addEventListener(`${prefix}fullscreenerror`, onError);
  1434. });
  1435. return () => {
  1436. prefixes.forEach((prefix) => {
  1437. element.removeEventListener(`${prefix}fullscreenchange`, onFullScreen);
  1438. element.removeEventListener(`${prefix}fullscreenerror`, onError);
  1439. });
  1440. };
  1441. }
  1442. function useFullscreen() {
  1443. const [fullscreen, setFullscreen] = React.useState(false);
  1444. const _ref = React.useRef(null);
  1445. const handleFullscreenChange = React.useCallback(
  1446. (event) => {
  1447. setFullscreen(event.target === getFullscreenElement());
  1448. },
  1449. [setFullscreen]
  1450. );
  1451. const handleFullscreenError = React.useCallback(
  1452. (event) => {
  1453. setFullscreen(false);
  1454. console.error(
  1455. `[@mantine/hooks] use-fullscreen: Error attempting full-screen mode method: ${event} (${event.target})`
  1456. );
  1457. },
  1458. [setFullscreen]
  1459. );
  1460. const toggle = React.useCallback(async () => {
  1461. if (!getFullscreenElement()) {
  1462. await enterFullScreen(_ref.current);
  1463. } else {
  1464. await exitFullscreen();
  1465. }
  1466. }, []);
  1467. const ref = React.useCallback((element) => {
  1468. if (element === null) {
  1469. _ref.current = window.document.documentElement;
  1470. } else {
  1471. _ref.current = element;
  1472. }
  1473. }, []);
  1474. React.useEffect(() => {
  1475. if (!_ref.current && window.document) {
  1476. _ref.current = window.document.documentElement;
  1477. return addEvents(_ref.current, {
  1478. onFullScreen: handleFullscreenChange,
  1479. onError: handleFullscreenError
  1480. });
  1481. }
  1482. if (_ref.current) {
  1483. return addEvents(_ref.current, {
  1484. onFullScreen: handleFullscreenChange,
  1485. onError: handleFullscreenError
  1486. });
  1487. }
  1488. return void 0;
  1489. }, [_ref.current]);
  1490. return { ref, toggle, fullscreen };
  1491. }
  1492. function useLogger(componentName, props) {
  1493. React.useEffect(() => {
  1494. console.log(`${componentName} mounted`, ...props);
  1495. return () => console.log(`${componentName} unmounted`);
  1496. }, []);
  1497. useDidUpdate(() => {
  1498. console.log(`${componentName} updated`, ...props);
  1499. }, props);
  1500. return null;
  1501. }
  1502. function useHover() {
  1503. const [hovered, setHovered] = React.useState(false);
  1504. const ref = React.useRef(null);
  1505. const onMouseEnter = React.useCallback(() => setHovered(true), []);
  1506. const onMouseLeave = React.useCallback(() => setHovered(false), []);
  1507. React.useEffect(() => {
  1508. if (ref.current) {
  1509. ref.current.addEventListener("mouseenter", onMouseEnter);
  1510. ref.current.addEventListener("mouseleave", onMouseLeave);
  1511. return () => {
  1512. ref.current?.removeEventListener("mouseenter", onMouseEnter);
  1513. ref.current?.removeEventListener("mouseleave", onMouseLeave);
  1514. };
  1515. }
  1516. return void 0;
  1517. }, [ref.current]);
  1518. return { ref, hovered };
  1519. }
  1520. function useValidatedState(initialValue, validation, initialValidationState) {
  1521. const [value, setValue] = React.useState(initialValue);
  1522. const [lastValidValue, setLastValidValue] = React.useState(
  1523. validation(initialValue) ? initialValue : void 0
  1524. );
  1525. const [valid, setValid] = React.useState(
  1526. typeof initialValidationState === "boolean" ? initialValidationState : validation(initialValue)
  1527. );
  1528. const onChange = (val) => {
  1529. if (validation(val)) {
  1530. setLastValidValue(val);
  1531. setValid(true);
  1532. } else {
  1533. setValid(false);
  1534. }
  1535. setValue(val);
  1536. };
  1537. return [{ value, lastValidValue, valid }, onChange];
  1538. }
  1539. function isMacOS(userAgent) {
  1540. const macosPattern = /(Macintosh)|(MacIntel)|(MacPPC)|(Mac68K)/i;
  1541. return macosPattern.test(userAgent);
  1542. }
  1543. function isIOS(userAgent) {
  1544. const iosPattern = /(iPhone)|(iPad)|(iPod)/i;
  1545. return iosPattern.test(userAgent);
  1546. }
  1547. function isWindows(userAgent) {
  1548. const windowsPattern = /(Win32)|(Win64)|(Windows)|(WinCE)/i;
  1549. return windowsPattern.test(userAgent);
  1550. }
  1551. function isAndroid(userAgent) {
  1552. const androidPattern = /Android/i;
  1553. return androidPattern.test(userAgent);
  1554. }
  1555. function isLinux(userAgent) {
  1556. const linuxPattern = /Linux/i;
  1557. return linuxPattern.test(userAgent);
  1558. }
  1559. function getOS() {
  1560. if (typeof window === "undefined") {
  1561. return "undetermined";
  1562. }
  1563. const { userAgent } = window.navigator;
  1564. if (isIOS(userAgent) || isMacOS(userAgent) && "ontouchend" in document) {
  1565. return "ios";
  1566. }
  1567. if (isMacOS(userAgent)) {
  1568. return "macos";
  1569. }
  1570. if (isWindows(userAgent)) {
  1571. return "windows";
  1572. }
  1573. if (isAndroid(userAgent)) {
  1574. return "android";
  1575. }
  1576. if (isLinux(userAgent)) {
  1577. return "linux";
  1578. }
  1579. return "undetermined";
  1580. }
  1581. function useOs(options = { getValueInEffect: true }) {
  1582. const [value, setValue] = React.useState(options.getValueInEffect ? "undetermined" : getOS());
  1583. useIsomorphicEffect(() => {
  1584. if (options.getValueInEffect) {
  1585. setValue(getOS);
  1586. }
  1587. }, []);
  1588. return value;
  1589. }
  1590. function useSetState(initialState) {
  1591. const [state, setState] = React.useState(initialState);
  1592. const _setState = React.useCallback(
  1593. (statePartial) => setState((current) => ({
  1594. ...current,
  1595. ...typeof statePartial === "function" ? statePartial(current) : statePartial
  1596. })),
  1597. []
  1598. );
  1599. return [state, _setState];
  1600. }
  1601. function getInputOnChange(setValue) {
  1602. return (val) => {
  1603. if (!val) {
  1604. setValue(val);
  1605. } else if (typeof val === "function") {
  1606. setValue(val);
  1607. } else if (typeof val === "object" && "nativeEvent" in val) {
  1608. const { currentTarget } = val;
  1609. if (currentTarget.type === "checkbox") {
  1610. setValue(currentTarget.checked);
  1611. } else {
  1612. setValue(currentTarget.value);
  1613. }
  1614. } else {
  1615. setValue(val);
  1616. }
  1617. };
  1618. }
  1619. function useInputState(initialState) {
  1620. const [value, setValue] = React.useState(initialState);
  1621. return [value, getInputOnChange(setValue)];
  1622. }
  1623. function useEventListener(type, listener, options) {
  1624. const ref = React.useRef(null);
  1625. React.useEffect(() => {
  1626. if (ref.current) {
  1627. ref.current.addEventListener(type, listener, options);
  1628. return () => ref.current?.removeEventListener(type, listener, options);
  1629. }
  1630. return void 0;
  1631. }, [listener, options]);
  1632. return ref;
  1633. }
  1634. function useDisclosure(initialState = false, callbacks) {
  1635. const { onOpen, onClose } = callbacks || {};
  1636. const [opened, setOpened] = React.useState(initialState);
  1637. const open = React.useCallback(() => {
  1638. setOpened((isOpened) => {
  1639. if (!isOpened) {
  1640. onOpen?.();
  1641. return true;
  1642. }
  1643. return isOpened;
  1644. });
  1645. }, [onOpen]);
  1646. const close = React.useCallback(() => {
  1647. setOpened((isOpened) => {
  1648. if (isOpened) {
  1649. onClose?.();
  1650. return false;
  1651. }
  1652. return isOpened;
  1653. });
  1654. }, [onClose]);
  1655. const toggle = React.useCallback(() => {
  1656. opened ? close() : open();
  1657. }, [close, open, opened]);
  1658. return [opened, { open, close, toggle }];
  1659. }
  1660. function containsRelatedTarget(event) {
  1661. if (event.currentTarget instanceof HTMLElement && event.relatedTarget instanceof HTMLElement) {
  1662. return event.currentTarget.contains(event.relatedTarget);
  1663. }
  1664. return false;
  1665. }
  1666. function useFocusWithin({
  1667. onBlur,
  1668. onFocus
  1669. } = {}) {
  1670. const ref = React.useRef(null);
  1671. const [focused, setFocused] = React.useState(false);
  1672. const focusedRef = React.useRef(false);
  1673. const _setFocused = (value) => {
  1674. setFocused(value);
  1675. focusedRef.current = value;
  1676. };
  1677. const handleFocusIn = (event) => {
  1678. if (!focusedRef.current) {
  1679. _setFocused(true);
  1680. onFocus?.(event);
  1681. }
  1682. };
  1683. const handleFocusOut = (event) => {
  1684. if (focusedRef.current && !containsRelatedTarget(event)) {
  1685. _setFocused(false);
  1686. onBlur?.(event);
  1687. }
  1688. };
  1689. React.useEffect(() => {
  1690. if (ref.current) {
  1691. ref.current.addEventListener("focusin", handleFocusIn);
  1692. ref.current.addEventListener("focusout", handleFocusOut);
  1693. return () => {
  1694. ref.current?.removeEventListener("focusin", handleFocusIn);
  1695. ref.current?.removeEventListener("focusout", handleFocusOut);
  1696. };
  1697. }
  1698. return void 0;
  1699. }, [handleFocusIn, handleFocusOut]);
  1700. return { ref, focused };
  1701. }
  1702. function getConnection() {
  1703. if (typeof navigator === "undefined") {
  1704. return {};
  1705. }
  1706. const _navigator = navigator;
  1707. const connection = _navigator.connection || _navigator.mozConnection || _navigator.webkitConnection;
  1708. if (!connection) {
  1709. return {};
  1710. }
  1711. return {
  1712. downlink: connection?.downlink,
  1713. downlinkMax: connection?.downlinkMax,
  1714. effectiveType: connection?.effectiveType,
  1715. rtt: connection?.rtt,
  1716. saveData: connection?.saveData,
  1717. type: connection?.type
  1718. };
  1719. }
  1720. function useNetwork() {
  1721. const [status, setStatus] = React.useState({
  1722. online: true
  1723. });
  1724. const handleConnectionChange = React.useCallback(
  1725. () => setStatus((current) => ({ ...current, ...getConnection() })),
  1726. []
  1727. );
  1728. useWindowEvent("online", () => setStatus({ online: true, ...getConnection() }));
  1729. useWindowEvent("offline", () => setStatus({ online: false, ...getConnection() }));
  1730. React.useEffect(() => {
  1731. const _navigator = navigator;
  1732. if (_navigator.connection) {
  1733. setStatus({ online: _navigator.onLine, ...getConnection() });
  1734. _navigator.connection.addEventListener("change", handleConnectionChange);
  1735. return () => _navigator.connection.removeEventListener("change", handleConnectionChange);
  1736. }
  1737. if (typeof _navigator.onLine === "boolean") {
  1738. setStatus((current) => ({ ...current, online: _navigator.onLine }));
  1739. }
  1740. return void 0;
  1741. }, []);
  1742. return status;
  1743. }
  1744. function useTimeout(callback, delay, options = { autoInvoke: false }) {
  1745. const timeoutRef = React.useRef(null);
  1746. const start = React.useCallback(
  1747. (...callbackParams) => {
  1748. if (!timeoutRef.current) {
  1749. timeoutRef.current = window.setTimeout(() => {
  1750. callback(callbackParams);
  1751. timeoutRef.current = null;
  1752. }, delay);
  1753. }
  1754. },
  1755. [delay]
  1756. );
  1757. const clear = React.useCallback(() => {
  1758. if (timeoutRef.current) {
  1759. window.clearTimeout(timeoutRef.current);
  1760. timeoutRef.current = null;
  1761. }
  1762. }, []);
  1763. React.useEffect(() => {
  1764. if (options.autoInvoke) {
  1765. start();
  1766. }
  1767. return clear;
  1768. }, [clear, start]);
  1769. return { start, clear };
  1770. }
  1771. function useTextSelection() {
  1772. const forceUpdate = useForceUpdate();
  1773. const [selection, setSelection] = React.useState(null);
  1774. const handleSelectionChange = () => {
  1775. setSelection(document.getSelection());
  1776. forceUpdate();
  1777. };
  1778. React.useEffect(() => {
  1779. setSelection(document.getSelection());
  1780. document.addEventListener("selectionchange", handleSelectionChange);
  1781. return () => document.removeEventListener("selectionchange", handleSelectionChange);
  1782. }, []);
  1783. return selection;
  1784. }
  1785. function usePrevious(value) {
  1786. const ref = React.useRef(void 0);
  1787. React.useEffect(() => {
  1788. ref.current = value;
  1789. }, [value]);
  1790. return ref.current;
  1791. }
  1792. var MIME_TYPES = {
  1793. ico: "image/x-icon",
  1794. png: "image/png",
  1795. svg: "image/svg+xml",
  1796. gif: "image/gif"
  1797. };
  1798. function useFavicon(url) {
  1799. const link = React.useRef(null);
  1800. useIsomorphicEffect(() => {
  1801. if (!url) {
  1802. return;
  1803. }
  1804. if (!link.current) {
  1805. const existingElements = document.querySelectorAll('link[rel*="icon"]');
  1806. existingElements.forEach((element2) => document.head.removeChild(element2));
  1807. const element = document.createElement("link");
  1808. element.rel = "shortcut icon";
  1809. link.current = element;
  1810. document.querySelector("head").appendChild(element);
  1811. }
  1812. const splittedUrl = url.split(".");
  1813. link.current.setAttribute(
  1814. "type",
  1815. MIME_TYPES[splittedUrl[splittedUrl.length - 1].toLowerCase()]
  1816. );
  1817. link.current.setAttribute("href", url);
  1818. }, [url]);
  1819. }
  1820. var isFixed = (current, fixedAt) => current <= fixedAt;
  1821. var isPinnedOrReleased = (current, fixedAt, isCurrentlyPinnedRef, isScrollingUp, onPin, onRelease) => {
  1822. const isInFixedPosition = isFixed(current, fixedAt);
  1823. if (isInFixedPosition && !isCurrentlyPinnedRef.current) {
  1824. isCurrentlyPinnedRef.current = true;
  1825. onPin?.();
  1826. } else if (!isInFixedPosition && isScrollingUp && !isCurrentlyPinnedRef.current) {
  1827. isCurrentlyPinnedRef.current = true;
  1828. onPin?.();
  1829. } else if (!isInFixedPosition && isCurrentlyPinnedRef.current) {
  1830. isCurrentlyPinnedRef.current = false;
  1831. onRelease?.();
  1832. }
  1833. };
  1834. var useScrollDirection = () => {
  1835. const [lastScrollTop, setLastScrollTop] = React.useState(0);
  1836. const [isScrollingUp, setIsScrollingUp] = React.useState(false);
  1837. const [isResizing, setIsResizing] = React.useState(false);
  1838. React.useEffect(() => {
  1839. let resizeTimer;
  1840. const onResize = () => {
  1841. setIsResizing(true);
  1842. clearTimeout(resizeTimer);
  1843. resizeTimer = setTimeout(() => {
  1844. setIsResizing(false);
  1845. }, 300);
  1846. };
  1847. const onScroll = () => {
  1848. if (isResizing) {
  1849. return;
  1850. }
  1851. const currentScrollTop = window.pageYOffset || document.documentElement.scrollTop;
  1852. setIsScrollingUp(currentScrollTop < lastScrollTop);
  1853. setLastScrollTop(currentScrollTop);
  1854. };
  1855. window.addEventListener("scroll", onScroll);
  1856. window.addEventListener("resize", onResize);
  1857. return () => {
  1858. window.removeEventListener("scroll", onScroll);
  1859. window.removeEventListener("resize", onResize);
  1860. };
  1861. }, [lastScrollTop, isResizing]);
  1862. return isScrollingUp;
  1863. };
  1864. function useHeadroom({ fixedAt = 0, onPin, onFix, onRelease } = {}) {
  1865. const isCurrentlyPinnedRef = React.useRef(false);
  1866. const isScrollingUp = useScrollDirection();
  1867. const [{ y: scrollPosition }] = useWindowScroll();
  1868. useIsomorphicEffect(() => {
  1869. isPinnedOrReleased(
  1870. scrollPosition,
  1871. fixedAt,
  1872. isCurrentlyPinnedRef,
  1873. isScrollingUp,
  1874. onPin,
  1875. onRelease
  1876. );
  1877. }, [scrollPosition]);
  1878. useIsomorphicEffect(() => {
  1879. if (isFixed(scrollPosition, fixedAt)) {
  1880. onFix?.();
  1881. }
  1882. }, [scrollPosition, fixedAt, onFix]);
  1883. if (isFixed(scrollPosition, fixedAt) || isScrollingUp) {
  1884. return true;
  1885. }
  1886. return false;
  1887. }
  1888. function isOpera() {
  1889. return navigator.userAgent.includes("OPR");
  1890. }
  1891. function useEyeDropper() {
  1892. const [supported, setSupported] = React.useState(false);
  1893. useIsomorphicEffect(() => {
  1894. setSupported(typeof window !== "undefined" && !isOpera() && "EyeDropper" in window);
  1895. }, []);
  1896. const open = React.useCallback(
  1897. (options = {}) => {
  1898. if (supported) {
  1899. const eyeDropper = new window.EyeDropper();
  1900. return eyeDropper.open(options);
  1901. }
  1902. return Promise.resolve(void 0);
  1903. },
  1904. [supported]
  1905. );
  1906. return { supported, open };
  1907. }
  1908. function useInViewport() {
  1909. const observer = React.useRef(null);
  1910. const [inViewport, setInViewport] = React.useState(false);
  1911. const ref = React.useCallback((node) => {
  1912. if (typeof IntersectionObserver !== "undefined") {
  1913. if (node && !observer.current) {
  1914. observer.current = new IntersectionObserver(
  1915. ([entry]) => setInViewport(entry.isIntersecting)
  1916. );
  1917. } else {
  1918. observer.current?.disconnect();
  1919. }
  1920. if (node) {
  1921. observer.current?.observe(node);
  1922. } else {
  1923. setInViewport(false);
  1924. }
  1925. }
  1926. }, []);
  1927. return { ref, inViewport };
  1928. }
  1929. function useMutationObserver(callback, options, target) {
  1930. const observer = React.useRef(null);
  1931. const ref = React.useRef(null);
  1932. React.useEffect(() => {
  1933. const targetElement = typeof target === "function" ? target() : target;
  1934. if (targetElement || ref.current) {
  1935. observer.current = new MutationObserver(callback);
  1936. observer.current.observe(targetElement || ref.current, options);
  1937. }
  1938. return () => {
  1939. observer.current?.disconnect();
  1940. };
  1941. }, [callback, options]);
  1942. return ref;
  1943. }
  1944. function useMounted() {
  1945. const [mounted, setMounted] = React.useState(false);
  1946. React.useEffect(() => setMounted(true), []);
  1947. return mounted;
  1948. }
  1949. function useStateHistory(initialValue) {
  1950. const [state, setState] = React.useState({
  1951. history: [initialValue],
  1952. current: 0
  1953. });
  1954. const set = React.useCallback(
  1955. (val) => setState((currentState) => {
  1956. const nextState = [...currentState.history.slice(0, currentState.current + 1), val];
  1957. return {
  1958. history: nextState,
  1959. current: nextState.length - 1
  1960. };
  1961. }),
  1962. []
  1963. );
  1964. const back = React.useCallback(
  1965. (steps = 1) => setState((currentState) => ({
  1966. history: currentState.history,
  1967. current: Math.max(0, currentState.current - steps)
  1968. })),
  1969. []
  1970. );
  1971. const forward = React.useCallback(
  1972. (steps = 1) => setState((currentState) => ({
  1973. history: currentState.history,
  1974. current: Math.min(currentState.history.length - 1, currentState.current + steps)
  1975. })),
  1976. []
  1977. );
  1978. const reset = React.useCallback(() => {
  1979. setState({ history: [initialValue], current: 0 });
  1980. }, [initialValue]);
  1981. const handlers = React.useMemo(() => ({ back, forward, reset, set }), [back, forward, reset, set]);
  1982. return [state.history[state.current], handlers, state];
  1983. }
  1984. function useMap(initialState) {
  1985. const mapRef = React.useRef(new Map(initialState));
  1986. const forceUpdate = useForceUpdate();
  1987. mapRef.current.set = (...args) => {
  1988. Map.prototype.set.apply(mapRef.current, args);
  1989. forceUpdate();
  1990. return mapRef.current;
  1991. };
  1992. mapRef.current.clear = (...args) => {
  1993. Map.prototype.clear.apply(mapRef.current, args);
  1994. forceUpdate();
  1995. };
  1996. mapRef.current.delete = (...args) => {
  1997. const res = Map.prototype.delete.apply(mapRef.current, args);
  1998. forceUpdate();
  1999. return res;
  2000. };
  2001. return mapRef.current;
  2002. }
  2003. function useSet(values) {
  2004. const setRef = React.useRef(new Set(values));
  2005. const forceUpdate = useForceUpdate();
  2006. setRef.current.add = (...args) => {
  2007. const res = Set.prototype.add.apply(setRef.current, args);
  2008. forceUpdate();
  2009. return res;
  2010. };
  2011. setRef.current.clear = (...args) => {
  2012. Set.prototype.clear.apply(setRef.current, args);
  2013. forceUpdate();
  2014. };
  2015. setRef.current.delete = (...args) => {
  2016. const res = Set.prototype.delete.apply(setRef.current, args);
  2017. forceUpdate();
  2018. return res;
  2019. };
  2020. return setRef.current;
  2021. }
  2022. function useThrottledCallbackWithClearTimeout(callback, wait) {
  2023. const handleCallback = useCallbackRef(callback);
  2024. const latestInArgsRef = React.useRef(null);
  2025. const latestOutArgsRef = React.useRef(null);
  2026. const active = React.useRef(true);
  2027. const waitRef = React.useRef(wait);
  2028. const timeoutRef = React.useRef(-1);
  2029. const clearTimeout2 = () => window.clearTimeout(timeoutRef.current);
  2030. const callThrottledCallback = React.useCallback(
  2031. (...args) => {
  2032. handleCallback(...args);
  2033. latestInArgsRef.current = args;
  2034. latestOutArgsRef.current = args;
  2035. active.current = false;
  2036. },
  2037. [handleCallback]
  2038. );
  2039. const timerCallback = React.useCallback(() => {
  2040. if (latestInArgsRef.current && latestInArgsRef.current !== latestOutArgsRef.current) {
  2041. callThrottledCallback(...latestInArgsRef.current);
  2042. timeoutRef.current = window.setTimeout(timerCallback, waitRef.current);
  2043. } else {
  2044. active.current = true;
  2045. }
  2046. }, [callThrottledCallback]);
  2047. const throttled = React.useCallback(
  2048. (...args) => {
  2049. if (active.current) {
  2050. callThrottledCallback(...args);
  2051. timeoutRef.current = window.setTimeout(timerCallback, waitRef.current);
  2052. } else {
  2053. latestInArgsRef.current = args;
  2054. }
  2055. },
  2056. [callThrottledCallback, timerCallback]
  2057. );
  2058. React.useEffect(() => {
  2059. waitRef.current = wait;
  2060. }, [wait]);
  2061. return [throttled, clearTimeout2];
  2062. }
  2063. function useThrottledCallback(callback, wait) {
  2064. return useThrottledCallbackWithClearTimeout(callback, wait)[0];
  2065. }
  2066. function useThrottledState(defaultValue, wait) {
  2067. const [value, setValue] = React.useState(defaultValue);
  2068. const [setThrottledValue, clearTimeout2] = useThrottledCallbackWithClearTimeout(setValue, wait);
  2069. React.useEffect(() => clearTimeout2, []);
  2070. return [value, setThrottledValue];
  2071. }
  2072. function useThrottledValue(value, wait) {
  2073. const [throttledValue, setThrottledValue] = React.useState(value);
  2074. const valueRef = React.useRef(value);
  2075. const [throttledSetValue, clearTimeout2] = useThrottledCallbackWithClearTimeout(
  2076. setThrottledValue,
  2077. wait
  2078. );
  2079. React.useEffect(() => {
  2080. if (value !== valueRef.current) {
  2081. valueRef.current = value;
  2082. throttledSetValue(value);
  2083. }
  2084. }, [throttledSetValue, value]);
  2085. React.useEffect(() => clearTimeout2, []);
  2086. return throttledValue;
  2087. }
  2088. function useIsFirstRender() {
  2089. const renderRef = React.useRef(true);
  2090. if (renderRef.current === true) {
  2091. renderRef.current = false;
  2092. return true;
  2093. }
  2094. return renderRef.current;
  2095. }
  2096. function useOrientation() {
  2097. const [orientation, setOrientation] = React.useState({ angle: 0, type: "landscape-primary" });
  2098. const handleOrientationChange = (event) => {
  2099. const target = event.currentTarget;
  2100. setOrientation({ angle: target?.angle || 0, type: target?.type || "landscape-primary" });
  2101. };
  2102. useIsomorphicEffect(() => {
  2103. window.screen.orientation?.addEventListener("change", handleOrientationChange);
  2104. return () => window.screen.orientation?.removeEventListener("change", handleOrientationChange);
  2105. }, []);
  2106. return orientation;
  2107. }
  2108. function useFetch(url, { autoInvoke = true, ...options } = {}) {
  2109. const [data, setData] = React.useState(null);
  2110. const [loading, setLoading] = React.useState(false);
  2111. const [error, setError] = React.useState(null);
  2112. const controller = React.useRef(null);
  2113. const refetch = React.useCallback(() => {
  2114. if (!url) {
  2115. return;
  2116. }
  2117. if (controller.current) {
  2118. controller.current.abort();
  2119. }
  2120. controller.current = new AbortController();
  2121. setLoading(true);
  2122. return fetch(url, { signal: controller.current.signal, ...options }).then((res) => res.json()).then((res) => {
  2123. setData(res);
  2124. setLoading(false);
  2125. return res;
  2126. }).catch((err) => {
  2127. setLoading(false);
  2128. if (err.name !== "AbortError") {
  2129. setError(err);
  2130. }
  2131. return err;
  2132. });
  2133. }, [url]);
  2134. const abort = React.useCallback(() => {
  2135. if (controller.current) {
  2136. controller.current?.abort("");
  2137. }
  2138. }, []);
  2139. React.useEffect(() => {
  2140. if (autoInvoke) {
  2141. refetch();
  2142. }
  2143. return () => {
  2144. if (controller.current) {
  2145. controller.current.abort("");
  2146. }
  2147. };
  2148. }, [refetch, autoInvoke]);
  2149. return { data, loading, error, refetch, abort };
  2150. }
  2151. function radiansToDegrees(radians) {
  2152. return radians * (180 / Math.PI);
  2153. }
  2154. function getElementCenter(element) {
  2155. const rect = element.getBoundingClientRect();
  2156. return [rect.left + rect.width / 2, rect.top + rect.height / 2];
  2157. }
  2158. function getAngle(coordinates, element) {
  2159. const center = getElementCenter(element);
  2160. const x = coordinates[0] - center[0];
  2161. const y = coordinates[1] - center[1];
  2162. const deg = radiansToDegrees(Math.atan2(x, y)) + 180;
  2163. return 360 - deg;
  2164. }
  2165. function toFixed(value, digits) {
  2166. return parseFloat(value.toFixed(digits));
  2167. }
  2168. function getDigitsAfterDot(value) {
  2169. return value.toString().split(".")[1]?.length || 0;
  2170. }
  2171. function normalizeRadialValue(degree, step) {
  2172. const clamped = clamp(degree, 0, 360);
  2173. const high = Math.ceil(clamped / step);
  2174. const low = Math.round(clamped / step);
  2175. return toFixed(
  2176. high >= clamped / step ? high * step === 360 ? 0 : high * step : low * step,
  2177. getDigitsAfterDot(step)
  2178. );
  2179. }
  2180. function useRadialMove(onChange, { step = 0.01, onChangeEnd, onScrubStart, onScrubEnd } = {}) {
  2181. const ref = React.useRef(null);
  2182. const mounted = React.useRef(false);
  2183. const [active, setActive] = React.useState(false);
  2184. React.useEffect(() => {
  2185. mounted.current = true;
  2186. }, []);
  2187. React.useEffect(() => {
  2188. const update = (event, done = false) => {
  2189. if (ref.current) {
  2190. ref.current.style.userSelect = "none";
  2191. const deg = getAngle([event.clientX, event.clientY], ref.current);
  2192. const newValue = normalizeRadialValue(deg, step || 1);
  2193. onChange(newValue);
  2194. done && onChangeEnd?.(newValue);
  2195. }
  2196. };
  2197. const beginTracking = () => {
  2198. onScrubStart?.();
  2199. setActive(true);
  2200. document.addEventListener("mousemove", handleMouseMove, false);
  2201. document.addEventListener("mouseup", handleMouseUp, false);
  2202. document.addEventListener("touchmove", handleTouchMove, { passive: false });
  2203. document.addEventListener("touchend", handleTouchEnd, false);
  2204. };
  2205. const endTracking = () => {
  2206. onScrubEnd?.();
  2207. setActive(false);
  2208. document.removeEventListener("mousemove", handleMouseMove, false);
  2209. document.removeEventListener("mouseup", handleMouseUp, false);
  2210. document.removeEventListener("touchmove", handleTouchMove, false);
  2211. document.removeEventListener("touchend", handleTouchEnd, false);
  2212. };
  2213. const onMouseDown = (event) => {
  2214. beginTracking();
  2215. update(event);
  2216. };
  2217. const handleMouseMove = (event) => {
  2218. update(event);
  2219. };
  2220. const handleMouseUp = (event) => {
  2221. update(event, true);
  2222. endTracking();
  2223. };
  2224. const handleTouchMove = (event) => {
  2225. event.preventDefault();
  2226. update(event.touches[0]);
  2227. };
  2228. const handleTouchEnd = (event) => {
  2229. update(event.changedTouches[0], true);
  2230. endTracking();
  2231. };
  2232. const handleTouchStart = (event) => {
  2233. event.preventDefault();
  2234. beginTracking();
  2235. update(event.touches[0]);
  2236. };
  2237. ref.current?.addEventListener("mousedown", onMouseDown);
  2238. ref.current?.addEventListener("touchstart", handleTouchStart, { passive: false });
  2239. return () => {
  2240. if (ref.current) {
  2241. ref.current.removeEventListener("mousedown", onMouseDown);
  2242. ref.current.removeEventListener("touchstart", handleTouchStart);
  2243. }
  2244. };
  2245. }, [onChange]);
  2246. return { ref, active };
  2247. }
  2248. exports.assignRef = assignRef;
  2249. exports.clamp = clamp;
  2250. exports.clampUseMovePosition = clampUseMovePosition;
  2251. exports.getHotkeyHandler = getHotkeyHandler;
  2252. exports.lowerFirst = lowerFirst;
  2253. exports.mergeRefs = mergeRefs;
  2254. exports.normalizeRadialValue = normalizeRadialValue;
  2255. exports.randomId = randomId;
  2256. exports.range = range;
  2257. exports.readLocalStorageValue = readLocalStorageValue;
  2258. exports.readSessionStorageValue = readSessionStorageValue;
  2259. exports.shallowEqual = shallowEqual;
  2260. exports.upperFirst = upperFirst;
  2261. exports.useCallbackRef = useCallbackRef;
  2262. exports.useClickOutside = useClickOutside;
  2263. exports.useClipboard = useClipboard;
  2264. exports.useColorScheme = useColorScheme;
  2265. exports.useCounter = useCounter;
  2266. exports.useDebouncedCallback = useDebouncedCallback;
  2267. exports.useDebouncedState = useDebouncedState;
  2268. exports.useDebouncedValue = useDebouncedValue;
  2269. exports.useDidUpdate = useDidUpdate;
  2270. exports.useDisclosure = useDisclosure;
  2271. exports.useDocumentTitle = useDocumentTitle;
  2272. exports.useDocumentVisibility = useDocumentVisibility;
  2273. exports.useElementSize = useElementSize;
  2274. exports.useEventListener = useEventListener;
  2275. exports.useEyeDropper = useEyeDropper;
  2276. exports.useFavicon = useFavicon;
  2277. exports.useFetch = useFetch;
  2278. exports.useFocusReturn = useFocusReturn;
  2279. exports.useFocusTrap = useFocusTrap;
  2280. exports.useFocusWithin = useFocusWithin;
  2281. exports.useForceUpdate = useForceUpdate;
  2282. exports.useFullscreen = useFullscreen;
  2283. exports.useHash = useHash;
  2284. exports.useHeadroom = useHeadroom;
  2285. exports.useHotkeys = useHotkeys;
  2286. exports.useHover = useHover;
  2287. exports.useId = useId;
  2288. exports.useIdle = useIdle;
  2289. exports.useInViewport = useInViewport;
  2290. exports.useInputState = useInputState;
  2291. exports.useIntersection = useIntersection;
  2292. exports.useInterval = useInterval;
  2293. exports.useIsFirstRender = useIsFirstRender;
  2294. exports.useIsomorphicEffect = useIsomorphicEffect;
  2295. exports.useListState = useListState;
  2296. exports.useLocalStorage = useLocalStorage;
  2297. exports.useLogger = useLogger;
  2298. exports.useMap = useMap;
  2299. exports.useMediaQuery = useMediaQuery;
  2300. exports.useMergedRef = useMergedRef;
  2301. exports.useMounted = useMounted;
  2302. exports.useMouse = useMouse;
  2303. exports.useMove = useMove;
  2304. exports.useMutationObserver = useMutationObserver;
  2305. exports.useNetwork = useNetwork;
  2306. exports.useOrientation = useOrientation;
  2307. exports.useOs = useOs;
  2308. exports.usePageLeave = usePageLeave;
  2309. exports.usePagination = usePagination;
  2310. exports.usePrevious = usePrevious;
  2311. exports.useQueue = useQueue;
  2312. exports.useRadialMove = useRadialMove;
  2313. exports.useReducedMotion = useReducedMotion;
  2314. exports.useResizeObserver = useResizeObserver;
  2315. exports.useScrollIntoView = useScrollIntoView;
  2316. exports.useSessionStorage = useSessionStorage;
  2317. exports.useSet = useSet;
  2318. exports.useSetState = useSetState;
  2319. exports.useShallowEffect = useShallowEffect;
  2320. exports.useStateHistory = useStateHistory;
  2321. exports.useTextSelection = useTextSelection;
  2322. exports.useThrottledCallback = useThrottledCallback;
  2323. exports.useThrottledState = useThrottledState;
  2324. exports.useThrottledValue = useThrottledValue;
  2325. exports.useTimeout = useTimeout;
  2326. exports.useToggle = useToggle;
  2327. exports.useUncontrolled = useUncontrolled;
  2328. exports.useValidatedState = useValidatedState;
  2329. exports.useViewportSize = useViewportSize;
  2330. exports.useWindowEvent = useWindowEvent;
  2331. exports.useWindowScroll = useWindowScroll;
  2332. }));

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址