@mantine/hooks 9.5.2 → 9.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/cjs/use-click-outside/use-click-outside.cjs.map +1 -1
  2. package/cjs/use-clipboard/use-clipboard.cjs.map +1 -1
  3. package/cjs/use-collapse/use-collapse.cjs +33 -6
  4. package/cjs/use-collapse/use-collapse.cjs.map +1 -1
  5. package/cjs/use-collapse/use-horizontal-collapse.cjs +30 -6
  6. package/cjs/use-collapse/use-horizontal-collapse.cjs.map +1 -1
  7. package/cjs/use-counter/use-counter.cjs.map +1 -1
  8. package/cjs/use-debounced-callback/use-debounced-callback.cjs.map +1 -1
  9. package/cjs/use-debounced-state/use-debounced-state.cjs.map +1 -1
  10. package/cjs/use-debounced-value/use-debounced-value.cjs.map +1 -1
  11. package/cjs/use-did-update/use-did-update.cjs +17 -5
  12. package/cjs/use-did-update/use-did-update.cjs.map +1 -1
  13. package/cjs/use-disclosure/use-disclosure.cjs.map +1 -1
  14. package/cjs/use-document-visibility/use-document-visibility.cjs.map +1 -1
  15. package/cjs/use-drag/use-drag.cjs.map +1 -1
  16. package/cjs/use-event-listener/use-event-listener.cjs.map +1 -1
  17. package/cjs/use-eye-dropper/use-eye-dropper.cjs.map +1 -1
  18. package/cjs/use-favicon/use-favicon.cjs.map +1 -1
  19. package/cjs/use-fetch/use-fetch.cjs.map +1 -1
  20. package/cjs/use-file-dialog/use-file-dialog.cjs.map +1 -1
  21. package/cjs/use-floating-window/use-floating-window.cjs.map +1 -1
  22. package/cjs/use-focus-return/use-focus-return.cjs.map +1 -1
  23. package/cjs/use-focus-trap/use-focus-trap.cjs.map +1 -1
  24. package/cjs/use-focus-within/use-focus-within.cjs.map +1 -1
  25. package/cjs/use-force-update/use-force-update.cjs.map +1 -1
  26. package/cjs/use-fullscreen/use-fullscreen.cjs.map +1 -1
  27. package/cjs/use-hash/use-hash.cjs.map +1 -1
  28. package/cjs/use-headroom/use-headroom.cjs.map +1 -1
  29. package/cjs/use-hotkeys/parse-hotkey.cjs.map +1 -1
  30. package/cjs/use-hotkeys/use-hotkeys.cjs.map +1 -1
  31. package/cjs/use-hover/use-hover.cjs.map +1 -1
  32. package/cjs/use-id/use-id.cjs +2 -1
  33. package/cjs/use-id/use-id.cjs.map +1 -1
  34. package/cjs/use-idle/use-idle.cjs.map +1 -1
  35. package/cjs/use-in-viewport/use-in-viewport.cjs.map +1 -1
  36. package/cjs/use-input-state/use-input-state.cjs.map +1 -1
  37. package/cjs/use-intersection/use-intersection.cjs.map +1 -1
  38. package/cjs/use-interval/use-interval.cjs +5 -9
  39. package/cjs/use-interval/use-interval.cjs.map +1 -1
  40. package/cjs/use-is-first-render/use-is-first-render.cjs.map +1 -1
  41. package/cjs/use-list-state/use-list-state.cjs.map +1 -1
  42. package/cjs/use-local-storage/create-storage.cjs.map +1 -1
  43. package/cjs/use-long-press/use-long-press.cjs +2 -1
  44. package/cjs/use-long-press/use-long-press.cjs.map +1 -1
  45. package/cjs/use-map/use-map.cjs.map +1 -1
  46. package/cjs/use-mask/use-mask.cjs +9 -7
  47. package/cjs/use-mask/use-mask.cjs.map +1 -1
  48. package/cjs/use-media-query/use-media-query.cjs.map +1 -1
  49. package/cjs/use-merged-ref/use-merged-ref.cjs.map +1 -1
  50. package/cjs/use-mounted/use-mounted.cjs.map +1 -1
  51. package/cjs/use-mouse/use-mouse.cjs.map +1 -1
  52. package/cjs/use-move/use-move.cjs.map +1 -1
  53. package/cjs/use-mutation-observer/use-mutation-observer.cjs.map +1 -1
  54. package/cjs/use-network/use-network.cjs.map +1 -1
  55. package/cjs/use-orientation/use-orientation.cjs.map +1 -1
  56. package/cjs/use-os/use-os.cjs.map +1 -1
  57. package/cjs/use-page-leave/use-page-leave.cjs.map +1 -1
  58. package/cjs/use-pagination/use-pagination.cjs.map +1 -1
  59. package/cjs/use-previous/use-previous.cjs.map +1 -1
  60. package/cjs/use-queue/use-queue.cjs.map +1 -1
  61. package/cjs/use-radial-move/use-radial-move.cjs.map +1 -1
  62. package/cjs/use-resize-observer/use-resize-observer.cjs.map +1 -1
  63. package/cjs/use-roving-index/use-roving-index.cjs +11 -14
  64. package/cjs/use-roving-index/use-roving-index.cjs.map +1 -1
  65. package/cjs/use-scroll-direction/use-scroll-direction.cjs.map +1 -1
  66. package/cjs/use-scroll-into-view/use-scroll-into-view.cjs.map +1 -1
  67. package/cjs/use-scroll-spy/use-scroll-spy.cjs.map +1 -1
  68. package/cjs/use-scroller/use-scroller.cjs.map +1 -1
  69. package/cjs/use-selection/use-selection.cjs.map +1 -1
  70. package/cjs/use-set/use-set.cjs.map +1 -1
  71. package/cjs/use-set-state/use-set-state.cjs.map +1 -1
  72. package/cjs/use-shallow-effect/use-shallow-effect.cjs.map +1 -1
  73. package/cjs/use-splitter/use-splitter.cjs.map +1 -1
  74. package/cjs/use-state-history/use-state-history.cjs.map +1 -1
  75. package/cjs/use-text-selection/use-text-selection.cjs.map +1 -1
  76. package/cjs/use-throttled-callback/use-throttled-callback.cjs.map +1 -1
  77. package/cjs/use-throttled-state/use-throttled-state.cjs.map +1 -1
  78. package/cjs/use-throttled-value/use-throttled-value.cjs.map +1 -1
  79. package/cjs/use-timeout/use-timeout.cjs.map +1 -1
  80. package/cjs/use-toggle/use-toggle.cjs.map +1 -1
  81. package/cjs/use-uncontrolled/use-uncontrolled.cjs.map +1 -1
  82. package/cjs/use-validated-state/use-validated-state.cjs.map +1 -1
  83. package/cjs/use-viewport-size/use-viewport-size.cjs.map +1 -1
  84. package/cjs/use-window-event/use-window-event.cjs.map +1 -1
  85. package/cjs/use-window-scroll/use-window-scroll.cjs.map +1 -1
  86. package/cjs/utils/use-callback-ref/use-callback-ref.cjs.map +1 -1
  87. package/esm/use-collapse/use-collapse.mjs +33 -7
  88. package/esm/use-collapse/use-collapse.mjs.map +1 -1
  89. package/esm/use-collapse/use-horizontal-collapse.mjs +30 -6
  90. package/esm/use-collapse/use-horizontal-collapse.mjs.map +1 -1
  91. package/esm/use-did-update/use-did-update.mjs +17 -5
  92. package/esm/use-did-update/use-did-update.mjs.map +1 -1
  93. package/esm/use-hotkeys/parse-hotkey.mjs.map +1 -1
  94. package/esm/use-id/use-id.mjs +2 -1
  95. package/esm/use-id/use-id.mjs.map +1 -1
  96. package/esm/use-interval/use-interval.mjs +5 -9
  97. package/esm/use-interval/use-interval.mjs.map +1 -1
  98. package/esm/use-local-storage/create-storage.mjs.map +1 -1
  99. package/esm/use-long-press/use-long-press.mjs +2 -1
  100. package/esm/use-long-press/use-long-press.mjs.map +1 -1
  101. package/esm/use-mask/use-mask.mjs +9 -7
  102. package/esm/use-mask/use-mask.mjs.map +1 -1
  103. package/esm/use-roving-index/use-roving-index.mjs +11 -14
  104. package/esm/use-roving-index/use-roving-index.mjs.map +1 -1
  105. package/lib/use-collapse/use-collapse.d.ts +1 -0
  106. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { useDidUpdate } from "../use-did-update/use-did-update.mjs";
3
3
  import { mergeRefs } from "../use-merged-ref/use-merged-ref.mjs";
4
+ import { isMeasured } from "./use-collapse.mjs";
4
5
  import { useEffectEvent, useRef, useState } from "react";
5
6
  import { flushSync } from "react-dom";
6
7
  //#region packages/@mantine/hooks/src/use-collapse/use-horizontal-collapse.ts
@@ -19,6 +20,7 @@ function useHorizontalCollapse({ transitionDuration, transitionTimingFunction =
19
20
  ...keepMounted ? {} : { display: "none" }
20
21
  };
21
22
  const onTransitionStartEvent = useEffectEvent(() => onTransitionStart?.());
23
+ const onTransitionEndEvent = useEffectEvent(() => onTransitionEnd?.());
22
24
  const elementRef = useRef(null);
23
25
  const [styles, setStylesRaw] = useState(expanded ? {} : collapsedStyles);
24
26
  const [state, setState] = useState(expanded ? "entered" : "exited");
@@ -35,9 +37,14 @@ function useHorizontalCollapse({ transitionDuration, transitionTimingFunction =
35
37
  const duration = transitionDuration ?? getAutoWidthDuration(width);
36
38
  return { transition: `width ${duration}ms ${transitionTimingFunction}, opacity ${duration}ms ${transitionTimingFunction}` };
37
39
  };
40
+ const transitionRef = useRef(0);
38
41
  useDidUpdate(() => {
42
+ transitionRef.current += 1;
43
+ const transitionId = transitionRef.current;
44
+ const isCurrentTransition = () => transitionRef.current === transitionId;
39
45
  if (transitionDuration !== 0) onTransitionStartEvent();
40
46
  if (expanded) window.requestAnimationFrame(() => {
47
+ if (!isCurrentTransition() || !elementRef.current) return;
41
48
  flushSync(() => setState("entering"));
42
49
  mergeStyles({
43
50
  willChange: "width",
@@ -45,7 +52,14 @@ function useHorizontalCollapse({ transitionDuration, transitionTimingFunction =
45
52
  overflow: "hidden"
46
53
  });
47
54
  window.requestAnimationFrame(() => {
55
+ if (!isCurrentTransition() || !elementRef.current) return;
48
56
  const width = getElementWidth(elementRef);
57
+ if (!isMeasured(width)) {
58
+ setStyles({});
59
+ setState("entered");
60
+ onTransitionEndEvent();
61
+ return;
62
+ }
49
63
  mergeStyles({
50
64
  ...getTransitionStyles(width),
51
65
  width
@@ -53,17 +67,27 @@ function useHorizontalCollapse({ transitionDuration, transitionTimingFunction =
53
67
  });
54
68
  });
55
69
  else window.requestAnimationFrame(() => {
70
+ if (!isCurrentTransition() || !elementRef.current) return;
56
71
  flushSync(() => setState("exiting"));
57
72
  const width = getElementWidth(elementRef);
73
+ if (!isMeasured(width)) {
74
+ setStyles(collapsedStyles);
75
+ setState("exited");
76
+ onTransitionEndEvent();
77
+ return;
78
+ }
58
79
  mergeStyles({
59
80
  ...getTransitionStyles(width),
60
81
  willChange: "width",
61
82
  width
62
83
  });
63
- window.requestAnimationFrame(() => mergeStyles({
64
- width: 0,
65
- overflow: "hidden"
66
- }));
84
+ window.requestAnimationFrame(() => {
85
+ if (!isCurrentTransition() || !elementRef.current) return;
86
+ mergeStyles({
87
+ width: 0,
88
+ overflow: "hidden"
89
+ });
90
+ });
67
91
  });
68
92
  }, [expanded]);
69
93
  const handleTransitionEnd = (event) => {
@@ -73,11 +97,11 @@ function useHorizontalCollapse({ transitionDuration, transitionTimingFunction =
73
97
  if (width === styles.width) setStyles({});
74
98
  else mergeStyles({ width });
75
99
  setState("entered");
76
- onTransitionEnd?.();
100
+ onTransitionEndEvent();
77
101
  } else if (styles.width === 0) {
78
102
  setStyles(collapsedStyles);
79
103
  setState("exited");
80
- onTransitionEnd?.();
104
+ onTransitionEndEvent();
81
105
  }
82
106
  };
83
107
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"use-horizontal-collapse.mjs","names":[],"sources":["../../src/use-collapse/use-horizontal-collapse.ts"],"sourcesContent":["import React, { CSSProperties, useEffectEvent, useRef, useState } from 'react';\nimport { flushSync } from 'react-dom';\nimport { useDidUpdate } from '../use-did-update/use-did-update';\nimport { mergeRefs } from '../use-merged-ref/use-merged-ref';\n\nfunction getAutoWidthDuration(width: number | string) {\n if (!width || typeof width === 'string') {\n return 0;\n }\n const constant = width / 36;\n return Math.round((4 + 15 * constant ** 0.25 + constant / 5) * 10);\n}\n\nexport function getElementWidth(elementRef: React.RefObject<HTMLElement | null>) {\n return elementRef.current ? elementRef.current.scrollWidth : 'auto';\n}\n\nexport interface UseHorizontalCollapseInput {\n /** Expanded state */\n expanded: boolean;\n\n /** Transition duration in milliseconds, by default calculated based on content width */\n transitionDuration?: number;\n\n /** Transition timing function, `ease` by default */\n transitionTimingFunction?: string;\n\n /** Called when transition ends */\n onTransitionEnd?: () => void;\n\n /** Called when transition starts */\n onTransitionStart?: () => void;\n\n /** If true, collapsed content is kept in the DOM and hidden with `display: none` styles */\n keepMounted?: boolean;\n}\n\ninterface GetHorizontalCollapsePropsInput {\n style?: CSSProperties;\n ref?: React.Ref<HTMLDivElement>;\n}\n\ninterface GetHorizontalCollapsePropsReturnValue {\n 'aria-hidden': boolean;\n inert: boolean;\n ref: React.RefCallback<HTMLDivElement>;\n onTransitionEnd: (event: React.TransitionEvent<Element>) => void;\n style: React.CSSProperties;\n}\n\nexport type UseHorizontalCollapseState = 'entering' | 'entered' | 'exiting' | 'exited';\n\nexport interface UseHorizontalCollapseReturnValue {\n /** Current transition state */\n state: UseHorizontalCollapseState;\n\n /** Props to pass down to the collapsible element */\n getCollapseProps: (\n input?: GetHorizontalCollapsePropsInput\n ) => GetHorizontalCollapsePropsReturnValue;\n}\n\nexport function useHorizontalCollapse({\n transitionDuration,\n transitionTimingFunction = 'ease',\n onTransitionEnd,\n onTransitionStart,\n expanded,\n keepMounted,\n}: UseHorizontalCollapseInput): UseHorizontalCollapseReturnValue {\n const collapsedStyles = {\n width: 0,\n overflow: 'hidden',\n ...(keepMounted ? {} : { display: 'none' }),\n };\n\n const onTransitionStartEvent = useEffectEvent(() => onTransitionStart?.());\n\n const elementRef = useRef<HTMLElement>(null);\n const [styles, setStylesRaw] = useState<CSSProperties>(expanded ? {} : collapsedStyles);\n const [state, setState] = useState<UseHorizontalCollapseState>(expanded ? 'entered' : 'exited');\n const setStyles = (newStyles: React.SetStateAction<CSSProperties>) => {\n flushSync(() => setStylesRaw(newStyles));\n };\n\n const mergeStyles = (newStyles: CSSProperties) => {\n setStyles((oldStyles) => ({ ...oldStyles, ...newStyles }));\n };\n\n const getTransitionStyles = (width: number | string) => {\n const duration = transitionDuration ?? getAutoWidthDuration(width);\n return {\n transition: `width ${duration}ms ${transitionTimingFunction}, opacity ${duration}ms ${transitionTimingFunction}`,\n };\n };\n\n useDidUpdate(() => {\n const shouldTransition = transitionDuration !== 0;\n\n if (shouldTransition) {\n onTransitionStartEvent();\n }\n\n if (expanded) {\n window.requestAnimationFrame(() => {\n flushSync(() => setState('entering'));\n mergeStyles({ willChange: 'width', display: 'block', overflow: 'hidden' });\n window.requestAnimationFrame(() => {\n const width = getElementWidth(elementRef);\n mergeStyles({ ...getTransitionStyles(width), width });\n });\n });\n } else {\n window.requestAnimationFrame(() => {\n flushSync(() => setState('exiting'));\n const width = getElementWidth(elementRef);\n mergeStyles({ ...getTransitionStyles(width), willChange: 'width', width });\n window.requestAnimationFrame(() => mergeStyles({ width: 0, overflow: 'hidden' }));\n });\n }\n }, [expanded]);\n\n const handleTransitionEnd = (event: React.TransitionEvent): void => {\n if (event.target !== elementRef.current || event.propertyName !== 'width') {\n return;\n }\n\n if (expanded) {\n const width = getElementWidth(elementRef);\n\n if (width === styles.width) {\n setStyles({});\n } else {\n mergeStyles({ width });\n }\n\n setState('entered');\n onTransitionEnd?.();\n } else if (styles.width === 0) {\n setStyles(collapsedStyles);\n setState('exited');\n onTransitionEnd?.();\n }\n };\n\n return {\n state,\n getCollapseProps: (input) => ({\n 'aria-hidden': !expanded,\n inert: !expanded,\n ref: mergeRefs(elementRef, input?.ref),\n onTransitionEnd: handleTransitionEnd,\n style: { boxSizing: 'border-box', ...input?.style, ...styles },\n }),\n };\n}\n\nexport namespace useHorizontalCollapse {\n export type Input = UseHorizontalCollapseInput;\n export type ReturnValue = UseHorizontalCollapseReturnValue;\n export type State = UseHorizontalCollapseState;\n}\n"],"mappings":";;;;;;AAKA,SAAS,qBAAqB,OAAwB;CACpD,IAAI,CAAC,SAAS,OAAO,UAAU,UAC7B,OAAO;CAET,MAAM,WAAW,QAAQ;CACzB,OAAO,KAAK,OAAO,IAAI,KAAK,YAAY,MAAO,WAAW,KAAK,EAAE;AACnE;AAEA,SAAgB,gBAAgB,YAAiD;CAC/E,OAAO,WAAW,UAAU,WAAW,QAAQ,cAAc;AAC/D;AA+CA,SAAgB,sBAAsB,EACpC,oBACA,2BAA2B,QAC3B,iBACA,mBACA,UACA,eAC+D;CAC/D,MAAM,kBAAkB;EACtB,OAAO;EACP,UAAU;EACV,GAAI,cAAc,CAAC,IAAI,EAAE,SAAS,OAAO;CAC3C;CAEA,MAAM,yBAAyB,qBAAqB,oBAAoB,CAAC;CAEzE,MAAM,aAAa,OAAoB,IAAI;CAC3C,MAAM,CAAC,QAAQ,gBAAgB,SAAwB,WAAW,CAAC,IAAI,eAAe;CACtF,MAAM,CAAC,OAAO,YAAY,SAAqC,WAAW,YAAY,QAAQ;CAC9F,MAAM,aAAa,cAAmD;EACpE,gBAAgB,aAAa,SAAS,CAAC;CACzC;CAEA,MAAM,eAAe,cAA6B;EAChD,WAAW,eAAe;GAAE,GAAG;GAAW,GAAG;EAAU,EAAE;CAC3D;CAEA,MAAM,uBAAuB,UAA2B;EACtD,MAAM,WAAW,sBAAsB,qBAAqB,KAAK;EACjE,OAAO,EACL,YAAY,SAAS,SAAS,KAAK,yBAAyB,YAAY,SAAS,KAAK,2BACxF;CACF;CAEA,mBAAmB;EAGjB,IAFyB,uBAAuB,GAG9C,uBAAuB;EAGzB,IAAI,UACF,OAAO,4BAA4B;GACjC,gBAAgB,SAAS,UAAU,CAAC;GACpC,YAAY;IAAE,YAAY;IAAS,SAAS;IAAS,UAAU;GAAS,CAAC;GACzE,OAAO,4BAA4B;IACjC,MAAM,QAAQ,gBAAgB,UAAU;IACxC,YAAY;KAAE,GAAG,oBAAoB,KAAK;KAAG;IAAM,CAAC;GACtD,CAAC;EACH,CAAC;OAED,OAAO,4BAA4B;GACjC,gBAAgB,SAAS,SAAS,CAAC;GACnC,MAAM,QAAQ,gBAAgB,UAAU;GACxC,YAAY;IAAE,GAAG,oBAAoB,KAAK;IAAG,YAAY;IAAS;GAAM,CAAC;GACzE,OAAO,4BAA4B,YAAY;IAAE,OAAO;IAAG,UAAU;GAAS,CAAC,CAAC;EAClF,CAAC;CAEL,GAAG,CAAC,QAAQ,CAAC;CAEb,MAAM,uBAAuB,UAAuC;EAClE,IAAI,MAAM,WAAW,WAAW,WAAW,MAAM,iBAAiB,SAChE;EAGF,IAAI,UAAU;GACZ,MAAM,QAAQ,gBAAgB,UAAU;GAExC,IAAI,UAAU,OAAO,OACnB,UAAU,CAAC,CAAC;QAEZ,YAAY,EAAE,MAAM,CAAC;GAGvB,SAAS,SAAS;GAClB,kBAAkB;EACpB,OAAO,IAAI,OAAO,UAAU,GAAG;GAC7B,UAAU,eAAe;GACzB,SAAS,QAAQ;GACjB,kBAAkB;EACpB;CACF;CAEA,OAAO;EACL;EACA,mBAAmB,WAAW;GAC5B,eAAe,CAAC;GAChB,OAAO,CAAC;GACR,KAAK,UAAU,YAAY,OAAO,GAAG;GACrC,iBAAiB;GACjB,OAAO;IAAE,WAAW;IAAc,GAAG,OAAO;IAAO,GAAG;GAAO;EAC/D;CACF;AACF"}
1
+ {"version":3,"file":"use-horizontal-collapse.mjs","names":[],"sources":["../../src/use-collapse/use-horizontal-collapse.ts"],"sourcesContent":["import React, { CSSProperties, useEffectEvent, useRef, useState } from 'react';\nimport { flushSync } from 'react-dom';\nimport { useDidUpdate } from '../use-did-update/use-did-update';\nimport { mergeRefs } from '../use-merged-ref/use-merged-ref';\nimport { isMeasured } from './use-collapse';\n\nfunction getAutoWidthDuration(width: number | string) {\n if (!width || typeof width === 'string') {\n return 0;\n }\n const constant = width / 36;\n return Math.round((4 + 15 * constant ** 0.25 + constant / 5) * 10);\n}\n\nexport function getElementWidth(elementRef: React.RefObject<HTMLElement | null>) {\n return elementRef.current ? elementRef.current.scrollWidth : 'auto';\n}\n\nexport interface UseHorizontalCollapseInput {\n /** Expanded state */\n expanded: boolean;\n\n /** Transition duration in milliseconds, by default calculated based on content width */\n transitionDuration?: number;\n\n /** Transition timing function, `ease` by default */\n transitionTimingFunction?: string;\n\n /** Called when transition ends */\n onTransitionEnd?: () => void;\n\n /** Called when transition starts */\n onTransitionStart?: () => void;\n\n /** If true, collapsed content is kept in the DOM and hidden with `display: none` styles */\n keepMounted?: boolean;\n}\n\ninterface GetHorizontalCollapsePropsInput {\n style?: CSSProperties;\n ref?: React.Ref<HTMLDivElement>;\n}\n\ninterface GetHorizontalCollapsePropsReturnValue {\n 'aria-hidden': boolean;\n inert: boolean;\n ref: React.RefCallback<HTMLDivElement>;\n onTransitionEnd: (event: React.TransitionEvent<Element>) => void;\n style: React.CSSProperties;\n}\n\nexport type UseHorizontalCollapseState = 'entering' | 'entered' | 'exiting' | 'exited';\n\nexport interface UseHorizontalCollapseReturnValue {\n /** Current transition state */\n state: UseHorizontalCollapseState;\n\n /** Props to pass down to the collapsible element */\n getCollapseProps: (\n input?: GetHorizontalCollapsePropsInput\n ) => GetHorizontalCollapsePropsReturnValue;\n}\n\nexport function useHorizontalCollapse({\n transitionDuration,\n transitionTimingFunction = 'ease',\n onTransitionEnd,\n onTransitionStart,\n expanded,\n keepMounted,\n}: UseHorizontalCollapseInput): UseHorizontalCollapseReturnValue {\n const collapsedStyles = {\n width: 0,\n overflow: 'hidden',\n ...(keepMounted ? {} : { display: 'none' }),\n };\n\n const onTransitionStartEvent = useEffectEvent(() => onTransitionStart?.());\n const onTransitionEndEvent = useEffectEvent(() => onTransitionEnd?.());\n\n const elementRef = useRef<HTMLElement>(null);\n const [styles, setStylesRaw] = useState<CSSProperties>(expanded ? {} : collapsedStyles);\n const [state, setState] = useState<UseHorizontalCollapseState>(expanded ? 'entered' : 'exited');\n const setStyles = (newStyles: React.SetStateAction<CSSProperties>) => {\n flushSync(() => setStylesRaw(newStyles));\n };\n\n const mergeStyles = (newStyles: CSSProperties) => {\n setStyles((oldStyles) => ({ ...oldStyles, ...newStyles }));\n };\n\n const getTransitionStyles = (width: number | string) => {\n const duration = transitionDuration ?? getAutoWidthDuration(width);\n return {\n transition: `width ${duration}ms ${transitionTimingFunction}, opacity ${duration}ms ${transitionTimingFunction}`,\n };\n };\n\n const transitionRef = useRef(0);\n\n useDidUpdate(() => {\n transitionRef.current += 1;\n const transitionId = transitionRef.current;\n const isCurrentTransition = () => transitionRef.current === transitionId;\n const shouldTransition = transitionDuration !== 0;\n\n if (shouldTransition) {\n onTransitionStartEvent();\n }\n\n if (expanded) {\n window.requestAnimationFrame(() => {\n if (!isCurrentTransition() || !elementRef.current) {\n return;\n }\n\n flushSync(() => setState('entering'));\n mergeStyles({ willChange: 'width', display: 'block', overflow: 'hidden' });\n window.requestAnimationFrame(() => {\n if (!isCurrentTransition() || !elementRef.current) {\n return;\n }\n\n const width = getElementWidth(elementRef);\n\n if (!isMeasured(width)) {\n setStyles({});\n setState('entered');\n onTransitionEndEvent();\n return;\n }\n\n mergeStyles({ ...getTransitionStyles(width), width });\n });\n });\n } else {\n window.requestAnimationFrame(() => {\n if (!isCurrentTransition() || !elementRef.current) {\n return;\n }\n\n flushSync(() => setState('exiting'));\n const width = getElementWidth(elementRef);\n\n if (!isMeasured(width)) {\n setStyles(collapsedStyles);\n setState('exited');\n onTransitionEndEvent();\n return;\n }\n\n mergeStyles({ ...getTransitionStyles(width), willChange: 'width', width });\n window.requestAnimationFrame(() => {\n if (!isCurrentTransition() || !elementRef.current) {\n return;\n }\n\n mergeStyles({ width: 0, overflow: 'hidden' });\n });\n });\n }\n }, [expanded]);\n\n const handleTransitionEnd = (event: React.TransitionEvent): void => {\n if (event.target !== elementRef.current || event.propertyName !== 'width') {\n return;\n }\n\n if (expanded) {\n const width = getElementWidth(elementRef);\n\n if (width === styles.width) {\n setStyles({});\n } else {\n mergeStyles({ width });\n }\n\n setState('entered');\n onTransitionEndEvent();\n } else if (styles.width === 0) {\n setStyles(collapsedStyles);\n setState('exited');\n onTransitionEndEvent();\n }\n };\n\n return {\n state,\n getCollapseProps: (input) => ({\n 'aria-hidden': !expanded,\n inert: !expanded,\n ref: mergeRefs(elementRef, input?.ref),\n onTransitionEnd: handleTransitionEnd,\n style: { boxSizing: 'border-box', ...input?.style, ...styles },\n }),\n };\n}\n\nexport namespace useHorizontalCollapse {\n export type Input = UseHorizontalCollapseInput;\n export type ReturnValue = UseHorizontalCollapseReturnValue;\n export type State = UseHorizontalCollapseState;\n}\n"],"mappings":"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"}
@@ -1,14 +1,26 @@
1
1
  "use client";
2
2
  import { useEffect, useRef } from "react";
3
3
  //#region packages/@mantine/hooks/src/use-did-update/use-did-update.ts
4
+ function dependenciesChanged(previous, next) {
5
+ return previous.length !== next.length || next.some((dep, index) => !Object.is(dep, previous[index]));
6
+ }
4
7
  function useDidUpdate(fn, dependencies) {
5
8
  const mounted = useRef(false);
6
- useEffect(() => () => {
7
- mounted.current = false;
8
- }, []);
9
+ const previousRender = useRef(null);
10
+ const previousDependencies = useRef(void 0);
11
+ const render = {};
9
12
  useEffect(() => {
10
- if (mounted.current) return fn();
11
- mounted.current = true;
13
+ const isSameRender = previousRender.current === render;
14
+ const previous = previousDependencies.current;
15
+ previousRender.current = render;
16
+ previousDependencies.current = dependencies;
17
+ if (!mounted.current) {
18
+ mounted.current = true;
19
+ return;
20
+ }
21
+ if (isSameRender) return;
22
+ if (dependencies && previous && !dependenciesChanged(previous, dependencies)) return;
23
+ return fn();
12
24
  }, dependencies);
13
25
  }
14
26
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"use-did-update.mjs","names":[],"sources":["../../src/use-did-update/use-did-update.ts"],"sourcesContent":["import { DependencyList, EffectCallback, useEffect, useRef } from 'react';\n\nexport function useDidUpdate(fn: EffectCallback, dependencies?: DependencyList) {\n const mounted = useRef(false);\n\n useEffect(\n () => () => {\n mounted.current = false;\n },\n []\n );\n\n useEffect(() => {\n if (mounted.current) {\n return fn();\n }\n\n mounted.current = true;\n return undefined;\n }, dependencies);\n}\n"],"mappings":";;;AAEA,SAAgB,aAAa,IAAoB,cAA+B;CAC9E,MAAM,UAAU,OAAO,KAAK;CAE5B,sBACc;EACV,QAAQ,UAAU;CACpB,GACA,CAAC,CACH;CAEA,gBAAgB;EACd,IAAI,QAAQ,SACV,OAAO,GAAG;EAGZ,QAAQ,UAAU;CAEpB,GAAG,YAAY;AACjB"}
1
+ {"version":3,"file":"use-did-update.mjs","names":[],"sources":["../../src/use-did-update/use-did-update.ts"],"sourcesContent":["import { DependencyList, EffectCallback, useEffect, useRef } from 'react';\n\nfunction dependenciesChanged(previous: DependencyList, next: DependencyList) {\n return (\n previous.length !== next.length || next.some((dep, index) => !Object.is(dep, previous[index]))\n );\n}\n\nexport function useDidUpdate(fn: EffectCallback, dependencies?: DependencyList) {\n const mounted = useRef(false);\n const previousRender = useRef<object>(null);\n const previousDependencies = useRef<DependencyList | undefined>(undefined);\n const render = {};\n\n useEffect(() => {\n const isSameRender = previousRender.current === render;\n const previous = previousDependencies.current;\n\n previousRender.current = render;\n previousDependencies.current = dependencies;\n\n if (!mounted.current) {\n mounted.current = true;\n return undefined;\n }\n\n if (isSameRender) {\n return undefined;\n }\n\n if (dependencies && previous && !dependenciesChanged(previous, dependencies)) {\n return undefined;\n }\n\n return fn();\n }, dependencies);\n}\n"],"mappings":";;;AAEA,SAAS,oBAAoB,UAA0B,MAAsB;CAC3E,OACE,SAAS,WAAW,KAAK,UAAU,KAAK,MAAM,KAAK,UAAU,CAAC,OAAO,GAAG,KAAK,SAAS,MAAM,CAAC;AAEjG;AAEA,SAAgB,aAAa,IAAoB,cAA+B;CAC9E,MAAM,UAAU,OAAO,KAAK;CAC5B,MAAM,iBAAiB,OAAe,IAAI;CAC1C,MAAM,uBAAuB,OAAmC,KAAA,CAAS;CACzE,MAAM,SAAS,CAAC;CAEhB,gBAAgB;EACd,MAAM,eAAe,eAAe,YAAY;EAChD,MAAM,WAAW,qBAAqB;EAEtC,eAAe,UAAU;EACzB,qBAAqB,UAAU;EAE/B,IAAI,CAAC,QAAQ,SAAS;GACpB,QAAQ,UAAU;GAClB;EACF;EAEA,IAAI,cACF;EAGF,IAAI,gBAAgB,YAAY,CAAC,oBAAoB,UAAU,YAAY,GACzE;EAGF,OAAO,GAAG;CACZ,GAAG,YAAY;AACjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"parse-hotkey.mjs","names":[],"sources":["../../src/use-hotkeys/parse-hotkey.ts"],"sourcesContent":["export interface KeyboardModifiers {\n alt: boolean;\n ctrl: boolean;\n meta: boolean;\n mod: boolean;\n shift: boolean;\n}\n\nexport interface Hotkey extends KeyboardModifiers {\n key?: string;\n}\n\ntype CheckHotkeyMatch = (event: KeyboardEvent) => boolean;\n\nconst keyNameMap: Record<string, string> = {\n ' ': 'space',\n ArrowLeft: 'arrowleft',\n ArrowRight: 'arrowright',\n ArrowUp: 'arrowup',\n ArrowDown: 'arrowdown',\n Escape: 'escape',\n Esc: 'escape',\n esc: 'escape',\n Enter: 'enter',\n Tab: 'tab',\n Backspace: 'backspace',\n Delete: 'delete',\n Insert: 'insert',\n Home: 'home',\n End: 'end',\n PageUp: 'pageup',\n PageDown: 'pagedown',\n '+': 'plus',\n '-': 'minus',\n '*': 'asterisk',\n '/': 'slash',\n};\n\nfunction normalizeKey(key: string): string {\n const lowerKey = key.replace('Key', '').toLowerCase();\n return keyNameMap[key] || lowerKey;\n}\n\nexport function parseHotkey(hotkey: string): Hotkey {\n const keys = hotkey\n .toLowerCase()\n .split('+')\n .map((part) => part.trim());\n\n const modifiers: KeyboardModifiers = {\n alt: keys.includes('alt'),\n ctrl: keys.includes('ctrl'),\n meta: keys.includes('meta'),\n mod: keys.includes('mod'),\n shift: keys.includes('shift'),\n };\n\n const reservedKeys = ['alt', 'ctrl', 'meta', 'shift', 'mod'];\n\n const freeKey = keys.find((key) => !reservedKeys.includes(key));\n\n return {\n ...modifiers,\n key: freeKey === '[plus]' ? '+' : freeKey,\n };\n}\n\nfunction isExactHotkey(hotkey: Hotkey, event: KeyboardEvent, usePhysicalKeys?: boolean): boolean {\n const { alt, ctrl, meta, mod, shift, key } = hotkey;\n const { altKey, ctrlKey, metaKey, shiftKey, key: pressedKey, code: pressedCode } = event;\n\n if (alt !== altKey) {\n return false;\n }\n\n if (mod) {\n if (!ctrlKey && !metaKey) {\n return false;\n }\n } else {\n if (ctrl !== ctrlKey) {\n return false;\n }\n if (meta !== metaKey) {\n return false;\n }\n }\n if (shift !== shiftKey) {\n return false;\n }\n\n if (\n key &&\n (usePhysicalKeys\n ? normalizeKey(pressedCode) === normalizeKey(key)\n : normalizeKey(pressedKey ?? pressedCode) === normalizeKey(key))\n ) {\n return true;\n }\n\n return false;\n}\n\nexport function getHotkeyMatcher(hotkey: string, usePhysicalKeys?: boolean): CheckHotkeyMatch {\n return (event) => isExactHotkey(parseHotkey(hotkey), event, usePhysicalKeys);\n}\n\nexport interface HotkeyItemOptions {\n preventDefault?: boolean;\n usePhysicalKeys?: boolean;\n}\n\ntype HotkeyItem = [string, (event: any) => void, HotkeyItemOptions?];\n\nexport function getHotkeyHandler(hotkeys: HotkeyItem[]) {\n return (event: React.KeyboardEvent<HTMLElement> | KeyboardEvent) => {\n const _event = 'nativeEvent' in event ? event.nativeEvent : event;\n hotkeys.forEach(\n ([hotkey, handler, options = { preventDefault: true, usePhysicalKeys: false }]) => {\n if (getHotkeyMatcher(hotkey, options.usePhysicalKeys)(_event)) {\n if (options.preventDefault) {\n event.preventDefault();\n }\n\n handler(_event);\n }\n }\n );\n };\n}\n"],"mappings":";;AAcA,MAAM,aAAqC;CACzC,KAAK;CACL,WAAW;CACX,YAAY;CACZ,SAAS;CACT,WAAW;CACX,QAAQ;CACR,KAAK;CACL,KAAK;CACL,OAAO;CACP,KAAK;CACL,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,MAAM;CACN,KAAK;CACL,QAAQ;CACR,UAAU;CACV,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;AACP;AAEA,SAAS,aAAa,KAAqB;CACzC,MAAM,WAAW,IAAI,QAAQ,OAAO,EAAE,CAAC,CAAC,YAAY;CACpD,OAAO,WAAW,QAAQ;AAC5B;AAEA,SAAgB,YAAY,QAAwB;CAClD,MAAM,OAAO,OACV,YAAY,CAAC,CACb,MAAM,GAAG,CAAC,CACV,KAAK,SAAS,KAAK,KAAK,CAAC;CAE5B,MAAM,YAA+B;EACnC,KAAK,KAAK,SAAS,KAAK;EACxB,MAAM,KAAK,SAAS,MAAM;EAC1B,MAAM,KAAK,SAAS,MAAM;EAC1B,KAAK,KAAK,SAAS,KAAK;EACxB,OAAO,KAAK,SAAS,OAAO;CAC9B;CAEA,MAAM,eAAe;EAAC;EAAO;EAAQ;EAAQ;EAAS;CAAK;CAE3D,MAAM,UAAU,KAAK,MAAM,QAAQ,CAAC,aAAa,SAAS,GAAG,CAAC;CAE9D,OAAO;EACL,GAAG;EACH,KAAK,YAAY,WAAW,MAAM;CACpC;AACF;AAEA,SAAS,cAAc,QAAgB,OAAsB,iBAAoC;CAC/F,MAAM,EAAE,KAAK,MAAM,MAAM,KAAK,OAAO,QAAQ;CAC7C,MAAM,EAAE,QAAQ,SAAS,SAAS,UAAU,KAAK,YAAY,MAAM,gBAAgB;CAEnF,IAAI,QAAQ,QACV,OAAO;CAGT,IAAI;MACE,CAAC,WAAW,CAAC,SACf,OAAO;CAAA,OAEJ;EACL,IAAI,SAAS,SACX,OAAO;EAET,IAAI,SAAS,SACX,OAAO;CAEX;CACA,IAAI,UAAU,UACZ,OAAO;CAGT,IACE,QACC,kBACG,aAAa,WAAW,MAAM,aAAa,GAAG,IAC9C,aAAa,cAAc,WAAW,MAAM,aAAa,GAAG,IAEhE,OAAO;CAGT,OAAO;AACT;AAEA,SAAgB,iBAAiB,QAAgB,iBAA6C;CAC5F,QAAQ,UAAU,cAAc,YAAY,MAAM,GAAG,OAAO,eAAe;AAC7E;AASA,SAAgB,iBAAiB,SAAuB;CACtD,QAAQ,UAA4D;EAClE,MAAM,SAAS,iBAAiB,QAAQ,MAAM,cAAc;EAC5D,QAAQ,SACL,CAAC,QAAQ,SAAS,UAAU;GAAE,gBAAgB;GAAM,iBAAiB;EAAM,OAAO;GACjF,IAAI,iBAAiB,QAAQ,QAAQ,eAAe,CAAC,CAAC,MAAM,GAAG;IAC7D,IAAI,QAAQ,gBACV,MAAM,eAAe;IAGvB,QAAQ,MAAM;GAChB;EACF,CACF;CACF;AACF"}
1
+ {"version":3,"file":"parse-hotkey.mjs","names":[],"sources":["../../src/use-hotkeys/parse-hotkey.ts"],"sourcesContent":["export interface KeyboardModifiers {\n alt: boolean;\n ctrl: boolean;\n meta: boolean;\n mod: boolean;\n shift: boolean;\n}\n\nexport interface Hotkey extends KeyboardModifiers {\n key?: string;\n}\n\ntype CheckHotkeyMatch = (event: KeyboardEvent) => boolean;\n\nconst keyNameMap: Record<string, string> = {\n ' ': 'space',\n ArrowLeft: 'arrowleft',\n ArrowRight: 'arrowright',\n ArrowUp: 'arrowup',\n ArrowDown: 'arrowdown',\n Escape: 'escape',\n Esc: 'escape',\n esc: 'escape',\n Enter: 'enter',\n Tab: 'tab',\n Backspace: 'backspace',\n Delete: 'delete',\n Insert: 'insert',\n Home: 'home',\n End: 'end',\n PageUp: 'pageup',\n PageDown: 'pagedown',\n '+': 'plus',\n '-': 'minus',\n '*': 'asterisk',\n '/': 'slash',\n};\n\nfunction normalizeKey(key: string): string {\n const lowerKey = key.replace('Key', '').toLowerCase();\n return keyNameMap[key] || lowerKey;\n}\n\nexport function parseHotkey(hotkey: string): Hotkey {\n const keys = hotkey\n .toLowerCase()\n .split('+')\n .map((part) => part.trim());\n\n const modifiers: KeyboardModifiers = {\n alt: keys.includes('alt'),\n ctrl: keys.includes('ctrl'),\n meta: keys.includes('meta'),\n mod: keys.includes('mod'),\n shift: keys.includes('shift'),\n };\n\n const reservedKeys = ['alt', 'ctrl', 'meta', 'shift', 'mod'];\n\n const freeKey = keys.find((key) => !reservedKeys.includes(key));\n\n return {\n ...modifiers,\n key: freeKey === '[plus]' ? '+' : freeKey,\n };\n}\n\nfunction isExactHotkey(hotkey: Hotkey, event: KeyboardEvent, usePhysicalKeys?: boolean): boolean {\n const { alt, ctrl, meta, mod, shift, key } = hotkey;\n const { altKey, ctrlKey, metaKey, shiftKey, key: pressedKey, code: pressedCode } = event;\n\n if (alt !== altKey) {\n return false;\n }\n\n if (mod) {\n if (!ctrlKey && !metaKey) {\n return false;\n }\n } else {\n if (ctrl !== ctrlKey) {\n return false;\n }\n if (meta !== metaKey) {\n return false;\n }\n }\n if (shift !== shiftKey) {\n return false;\n }\n\n if (\n key &&\n (usePhysicalKeys\n ? normalizeKey(pressedCode) === normalizeKey(key)\n : normalizeKey(pressedKey ?? pressedCode) === normalizeKey(key))\n ) {\n return true;\n }\n\n return false;\n}\n\nexport function getHotkeyMatcher(hotkey: string, usePhysicalKeys?: boolean): CheckHotkeyMatch {\n return (event) => isExactHotkey(parseHotkey(hotkey), event, usePhysicalKeys);\n}\n\nexport interface HotkeyItemOptions {\n preventDefault?: boolean;\n usePhysicalKeys?: boolean;\n}\n\ntype HotkeyItem = [string, (event: any) => void, HotkeyItemOptions?];\n\nexport function getHotkeyHandler(hotkeys: HotkeyItem[]) {\n return (event: React.KeyboardEvent<HTMLElement> | KeyboardEvent) => {\n const _event = 'nativeEvent' in event ? event.nativeEvent : event;\n hotkeys.forEach(\n ([hotkey, handler, options = { preventDefault: true, usePhysicalKeys: false }]) => {\n if (getHotkeyMatcher(hotkey, options.usePhysicalKeys)(_event)) {\n if (options.preventDefault) {\n event.preventDefault();\n }\n\n handler(_event);\n }\n }\n );\n };\n}\n"],"mappings":";;AAcA,MAAM,aAAqC;CACzC,KAAK;CACL,WAAW;CACX,YAAY;CACZ,SAAS;CACT,WAAW;CACX,QAAQ;CACR,KAAK;CACL,KAAK;CACL,OAAO;CACP,KAAK;CACL,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,MAAM;CACN,KAAK;CACL,QAAQ;CACR,UAAU;CACV,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;AACP;AAEA,SAAS,aAAa,KAAqB;CACzC,MAAM,WAAW,IAAI,QAAQ,OAAO,EAAE,CAAC,CAAC,YAAY;CACpD,OAAO,WAAW,QAAQ;AAC5B;AAEA,SAAgB,YAAY,QAAwB;CAClD,MAAM,OAAO,OACV,YAAY,CAAC,CACb,MAAM,GAAG,CAAC,CACV,KAAK,SAAS,KAAK,KAAK,CAAC;CAE5B,MAAM,YAA+B;EACnC,KAAK,KAAK,SAAS,KAAK;EACxB,MAAM,KAAK,SAAS,MAAM;EAC1B,MAAM,KAAK,SAAS,MAAM;EAC1B,KAAK,KAAK,SAAS,KAAK;EACxB,OAAO,KAAK,SAAS,OAAO;CAC9B;CAEA,MAAM,eAAe;EAAC;EAAO;EAAQ;EAAQ;EAAS;CAAK;CAE3D,MAAM,UAAU,KAAK,MAAM,QAAQ,CAAC,aAAa,SAAS,GAAG,CAAC;CAE9D,OAAO;EACL,GAAG;EACH,KAAK,YAAY,WAAW,MAAM;CACpC;AACF;AAEA,SAAS,cAAc,QAAgB,OAAsB,iBAAoC;CAC/F,MAAM,EAAE,KAAK,MAAM,MAAM,KAAK,OAAO,QAAQ;CAC7C,MAAM,EAAE,QAAQ,SAAS,SAAS,UAAU,KAAK,YAAY,MAAM,gBAAgB;CAEnF,IAAI,QAAQ,QACV,OAAO;CAGT,IAAI,KACE;MAAA,CAAC,WAAW,CAAC,SACf,OAAO;CAAA,OAEJ;EACL,IAAI,SAAS,SACX,OAAO;EAET,IAAI,SAAS,SACX,OAAO;CAEX;CACA,IAAI,UAAU,UACZ,OAAO;CAGT,IACE,QACC,kBACG,aAAa,WAAW,MAAM,aAAa,GAAG,IAC9C,aAAa,cAAc,WAAW,MAAM,aAAa,GAAG,IAEhE,OAAO;CAGT,OAAO;AACT;AAEA,SAAgB,iBAAiB,QAAgB,iBAA6C;CAC5F,QAAQ,UAAU,cAAc,YAAY,MAAM,GAAG,OAAO,eAAe;AAC7E;AASA,SAAgB,iBAAiB,SAAuB;CACtD,QAAQ,UAA4D;EAClE,MAAM,SAAS,iBAAiB,QAAQ,MAAM,cAAc;EAC5D,QAAQ,SACL,CAAC,QAAQ,SAAS,UAAU;GAAE,gBAAgB;GAAM,iBAAiB;EAAM,OAAO;GACjF,IAAI,iBAAiB,QAAQ,QAAQ,eAAe,CAAC,CAAC,MAAM,GAAG;IAC7D,IAAI,QAAQ,gBACV,MAAM,eAAe;IAGvB,QAAQ,MAAM;GAChB;EACF,CACF;CACF;AACF"}
@@ -4,7 +4,8 @@ import { useIsomorphicEffect } from "../use-isomorphic-effect/use-isomorphic-eff
4
4
  import { useId, useRef, useState } from "react";
5
5
  //#region packages/@mantine/hooks/src/use-id/use-id.ts
6
6
  function useId$1(staticId) {
7
- const [uuid, setUuid] = useState(`mantine-${useId().replace(/:/g, "")}`);
7
+ const reactId = useId();
8
+ const [uuid, setUuid] = useState(`mantine-${reactId.replace(/:/g, "")}`);
8
9
  const hasInitializedRef = useRef(false);
9
10
  useIsomorphicEffect(() => {
10
11
  if (hasInitializedRef.current) return;
@@ -1 +1 @@
1
- {"version":3,"file":"use-id.mjs","names":["useId","useReactId"],"sources":["../../src/use-id/use-id.ts"],"sourcesContent":["import { useId as useReactId, useRef, useState } from 'react';\nimport { useIsomorphicEffect } from '../use-isomorphic-effect/use-isomorphic-effect';\nimport { randomId } from '../utils';\n\nexport function useId(staticId?: string) {\n const reactId = useReactId();\n const [uuid, setUuid] = useState(`mantine-${reactId.replace(/:/g, '')}`);\n const hasInitializedRef = useRef(false);\n\n useIsomorphicEffect(() => {\n if (hasInitializedRef.current) {\n return;\n }\n hasInitializedRef.current = true;\n setUuid(randomId());\n }, []);\n\n if (typeof staticId === 'string') {\n return staticId;\n }\n\n return uuid;\n}\n"],"mappings":";;;;;AAIA,SAAgBA,QAAM,UAAmB;CAEvC,MAAM,CAAC,MAAM,WAAW,SAAS,WADjBC,MACkC,CAAC,CAAC,QAAQ,MAAM,EAAE,GAAG;CACvE,MAAM,oBAAoB,OAAO,KAAK;CAEtC,0BAA0B;EACxB,IAAI,kBAAkB,SACpB;EAEF,kBAAkB,UAAU;EAC5B,QAAQ,SAAS,CAAC;CACpB,GAAG,CAAC,CAAC;CAEL,IAAI,OAAO,aAAa,UACtB,OAAO;CAGT,OAAO;AACT"}
1
+ {"version":3,"file":"use-id.mjs","names":["useId","useReactId"],"sources":["../../src/use-id/use-id.ts"],"sourcesContent":["import { useId as useReactId, useRef, useState } from 'react';\nimport { useIsomorphicEffect } from '../use-isomorphic-effect/use-isomorphic-effect';\nimport { randomId } from '../utils';\n\nexport function useId(staticId?: string) {\n const reactId = useReactId();\n const [uuid, setUuid] = useState(`mantine-${reactId.replace(/:/g, '')}`);\n const hasInitializedRef = useRef(false);\n\n useIsomorphicEffect(() => {\n if (hasInitializedRef.current) {\n return;\n }\n hasInitializedRef.current = true;\n setUuid(randomId());\n }, []);\n\n if (typeof staticId === 'string') {\n return staticId;\n }\n\n return uuid;\n}\n"],"mappings":";;;;;AAIA,SAAgBA,QAAM,UAAmB;CACvC,MAAM,UAAUC,MAAW;CAC3B,MAAM,CAAC,MAAM,WAAW,SAAS,WAAW,QAAQ,QAAQ,MAAM,EAAE,GAAG;CACvE,MAAM,oBAAoB,OAAO,KAAK;CAEtC,0BAA0B;EACxB,IAAI,kBAAkB,SACpB;EAEF,kBAAkB,UAAU;EAC5B,QAAQ,SAAS,CAAC;CACpB,GAAG,CAAC,CAAC;CAEL,IAAI,OAAO,aAAa,UACtB,OAAO;CAGT,OAAO;AACT"}
@@ -1,15 +1,16 @@
1
1
  "use client";
2
+ import { useCallbackRef } from "../utils/use-callback-ref/use-callback-ref.mjs";
2
3
  import { useCallback, useEffect, useRef, useState } from "react";
3
4
  //#region packages/@mantine/hooks/src/use-interval/use-interval.ts
4
5
  function useInterval(fn, interval, { autoInvoke = false } = {}) {
5
6
  const [active, setActive] = useState(false);
6
7
  const intervalRef = useRef(null);
7
- const fnRef = useRef(null);
8
+ const handleCallback = useCallbackRef(fn);
8
9
  const intervalValueRef = useRef(interval);
9
10
  intervalValueRef.current = interval;
10
11
  const start = useCallback(() => {
11
12
  setActive((old) => {
12
- if (!old && !intervalRef.current) intervalRef.current = window.setInterval(fnRef.current, intervalValueRef.current);
13
+ if (!old && !intervalRef.current) intervalRef.current = window.setInterval(handleCallback, intervalValueRef.current);
13
14
  return true;
14
15
  });
15
16
  }, []);
@@ -25,19 +26,14 @@ function useInterval(fn, interval, { autoInvoke = false } = {}) {
25
26
  intervalRef.current = null;
26
27
  return false;
27
28
  }
28
- if (!intervalRef.current) intervalRef.current = window.setInterval(fnRef.current, intervalValueRef.current);
29
+ if (!intervalRef.current) intervalRef.current = window.setInterval(handleCallback, intervalValueRef.current);
29
30
  return true;
30
31
  });
31
32
  }, []);
32
33
  useEffect(() => {
33
- fnRef.current = fn;
34
34
  active && start();
35
35
  return stop;
36
- }, [
37
- fn,
38
- active,
39
- interval
40
- ]);
36
+ }, [active, interval]);
41
37
  useEffect(() => {
42
38
  if (autoInvoke) start();
43
39
  }, []);
@@ -1 +1 @@
1
- {"version":3,"file":"use-interval.mjs","names":[],"sources":["../../src/use-interval/use-interval.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface UseIntervalOptions {\n /** If set, the interval will start automatically when the component is mounted, `false` by default */\n autoInvoke?: boolean;\n}\n\nexport interface UseIntervalReturnValue {\n /** Starts the interval */\n start: () => void;\n\n /** Stops the interval */\n stop: () => void;\n\n /** Toggles the interval */\n toggle: () => void;\n\n /** Indicates if the interval is active */\n active: boolean;\n}\n\nexport function useInterval(\n fn: () => void,\n interval: number,\n { autoInvoke = false }: UseIntervalOptions = {}\n): UseIntervalReturnValue {\n const [active, setActive] = useState(false);\n const intervalRef = useRef<number | null>(null);\n const fnRef = useRef<() => void>(null);\n const intervalValueRef = useRef(interval);\n intervalValueRef.current = interval;\n\n const start = useCallback(() => {\n setActive((old) => {\n if (!old && !intervalRef.current) {\n intervalRef.current = window.setInterval(fnRef.current!, intervalValueRef.current);\n }\n return true;\n });\n }, []);\n\n const stop = useCallback(() => {\n setActive(false);\n if (intervalRef.current) {\n window.clearInterval(intervalRef.current);\n }\n intervalRef.current = null;\n }, []);\n\n const toggle = useCallback(() => {\n setActive((current) => {\n if (current) {\n if (intervalRef.current) {\n window.clearInterval(intervalRef.current);\n }\n intervalRef.current = null;\n return false;\n }\n if (!intervalRef.current) {\n intervalRef.current = window.setInterval(fnRef.current!, intervalValueRef.current);\n }\n return true;\n });\n }, []);\n\n useEffect(() => {\n fnRef.current = fn;\n active && start();\n return stop;\n }, [fn, active, interval]);\n\n useEffect(() => {\n if (autoInvoke) {\n start();\n }\n }, []);\n\n return { start, stop, toggle, active };\n}\n\nexport namespace useInterval {\n export type Options = UseIntervalOptions;\n export type ReturnValue = UseIntervalReturnValue;\n}\n"],"mappings":";;;AAqBA,SAAgB,YACd,IACA,UACA,EAAE,aAAa,UAA8B,CAAC,GACtB;CACxB,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAC1C,MAAM,cAAc,OAAsB,IAAI;CAC9C,MAAM,QAAQ,OAAmB,IAAI;CACrC,MAAM,mBAAmB,OAAO,QAAQ;CACxC,iBAAiB,UAAU;CAE3B,MAAM,QAAQ,kBAAkB;EAC9B,WAAW,QAAQ;GACjB,IAAI,CAAC,OAAO,CAAC,YAAY,SACvB,YAAY,UAAU,OAAO,YAAY,MAAM,SAAU,iBAAiB,OAAO;GAEnF,OAAO;EACT,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,MAAM,OAAO,kBAAkB;EAC7B,UAAU,KAAK;EACf,IAAI,YAAY,SACd,OAAO,cAAc,YAAY,OAAO;EAE1C,YAAY,UAAU;CACxB,GAAG,CAAC,CAAC;CAEL,MAAM,SAAS,kBAAkB;EAC/B,WAAW,YAAY;GACrB,IAAI,SAAS;IACX,IAAI,YAAY,SACd,OAAO,cAAc,YAAY,OAAO;IAE1C,YAAY,UAAU;IACtB,OAAO;GACT;GACA,IAAI,CAAC,YAAY,SACf,YAAY,UAAU,OAAO,YAAY,MAAM,SAAU,iBAAiB,OAAO;GAEnF,OAAO;EACT,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,MAAM,UAAU;EAChB,UAAU,MAAM;EAChB,OAAO;CACT,GAAG;EAAC;EAAI;EAAQ;CAAQ,CAAC;CAEzB,gBAAgB;EACd,IAAI,YACF,MAAM;CAEV,GAAG,CAAC,CAAC;CAEL,OAAO;EAAE;EAAO;EAAM;EAAQ;CAAO;AACvC"}
1
+ {"version":3,"file":"use-interval.mjs","names":[],"sources":["../../src/use-interval/use-interval.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useCallbackRef } from '../utils';\n\nexport interface UseIntervalOptions {\n /** If set, the interval will start automatically when the component is mounted, `false` by default */\n autoInvoke?: boolean;\n}\n\nexport interface UseIntervalReturnValue {\n /** Starts the interval */\n start: () => void;\n\n /** Stops the interval */\n stop: () => void;\n\n /** Toggles the interval */\n toggle: () => void;\n\n /** Indicates if the interval is active */\n active: boolean;\n}\n\nexport function useInterval(\n fn: () => void,\n interval: number,\n { autoInvoke = false }: UseIntervalOptions = {}\n): UseIntervalReturnValue {\n const [active, setActive] = useState(false);\n const intervalRef = useRef<number | null>(null);\n const handleCallback = useCallbackRef(fn);\n const intervalValueRef = useRef(interval);\n intervalValueRef.current = interval;\n\n const start = useCallback(() => {\n setActive((old) => {\n if (!old && !intervalRef.current) {\n intervalRef.current = window.setInterval(handleCallback, intervalValueRef.current);\n }\n return true;\n });\n }, []);\n\n const stop = useCallback(() => {\n setActive(false);\n if (intervalRef.current) {\n window.clearInterval(intervalRef.current);\n }\n intervalRef.current = null;\n }, []);\n\n const toggle = useCallback(() => {\n setActive((current) => {\n if (current) {\n if (intervalRef.current) {\n window.clearInterval(intervalRef.current);\n }\n intervalRef.current = null;\n return false;\n }\n if (!intervalRef.current) {\n intervalRef.current = window.setInterval(handleCallback, intervalValueRef.current);\n }\n return true;\n });\n }, []);\n\n useEffect(() => {\n active && start();\n return stop;\n }, [active, interval]);\n\n useEffect(() => {\n if (autoInvoke) {\n start();\n }\n }, []);\n\n return { start, stop, toggle, active };\n}\n\nexport namespace useInterval {\n export type Options = UseIntervalOptions;\n export type ReturnValue = UseIntervalReturnValue;\n}\n"],"mappings":";;;;AAsBA,SAAgB,YACd,IACA,UACA,EAAE,aAAa,UAA8B,CAAC,GACtB;CACxB,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAC1C,MAAM,cAAc,OAAsB,IAAI;CAC9C,MAAM,iBAAiB,eAAe,EAAE;CACxC,MAAM,mBAAmB,OAAO,QAAQ;CACxC,iBAAiB,UAAU;CAE3B,MAAM,QAAQ,kBAAkB;EAC9B,WAAW,QAAQ;GACjB,IAAI,CAAC,OAAO,CAAC,YAAY,SACvB,YAAY,UAAU,OAAO,YAAY,gBAAgB,iBAAiB,OAAO;GAEnF,OAAO;EACT,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,MAAM,OAAO,kBAAkB;EAC7B,UAAU,KAAK;EACf,IAAI,YAAY,SACd,OAAO,cAAc,YAAY,OAAO;EAE1C,YAAY,UAAU;CACxB,GAAG,CAAC,CAAC;CAEL,MAAM,SAAS,kBAAkB;EAC/B,WAAW,YAAY;GACrB,IAAI,SAAS;IACX,IAAI,YAAY,SACd,OAAO,cAAc,YAAY,OAAO;IAE1C,YAAY,UAAU;IACtB,OAAO;GACT;GACA,IAAI,CAAC,YAAY,SACf,YAAY,UAAU,OAAO,YAAY,gBAAgB,iBAAiB,OAAO;GAEnF,OAAO;EACT,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,UAAU,MAAM;EAChB,OAAO;CACT,GAAG,CAAC,QAAQ,QAAQ,CAAC;CAErB,gBAAgB;EACd,IAAI,YACF,MAAM;CAEV,GAAG,CAAC,CAAC;CAEL,OAAO;EAAE;EAAO;EAAM;EAAQ;CAAO;AACvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-storage.mjs","names":[],"sources":["../../src/use-local-storage/create-storage.ts"],"sourcesContent":["/* oxlint-disable no-console */\nimport { useCallback, useEffect, useState } from 'react';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\nexport type StorageType = 'localStorage' | 'sessionStorage';\n\nexport interface UseStorageOptions<T> {\n /** Storage key */\n key: string;\n\n /** Default value that will be set if value is not found in storage */\n defaultValue?: T;\n\n /** If set to true, value will be updated in useEffect after mount. Default value is true. */\n getInitialValueInEffect?: boolean;\n\n /** Determines whether the value must be synced between browser tabs, `true` by default */\n sync?: boolean;\n\n /** Function to serialize value into string to be save in storage */\n serialize?: (value: T) => string;\n\n /** Function to deserialize string value from storage to value */\n deserialize?: (value: string | undefined) => T;\n}\n\nfunction serializeJSON<T>(value: T, hookName: string = 'use-local-storage') {\n try {\n return JSON.stringify(value);\n } catch (error) {\n throw new Error(`@mantine/hooks ${hookName}: Failed to serialize the value`);\n }\n}\n\nfunction deserializeJSON(value: string | undefined) {\n try {\n return value && JSON.parse(value);\n } catch {\n return value;\n }\n}\n\nfunction createStorageHandler(type: StorageType) {\n const getItem = (key: string) => {\n try {\n return window[type].getItem(key);\n } catch (error) {\n console.warn('use-local-storage: Failed to get value from storage, localStorage is blocked');\n return null;\n }\n };\n\n const setItem = (key: string, value: string) => {\n try {\n window[type].setItem(key, value);\n } catch (error) {\n console.warn('use-local-storage: Failed to set value to storage, localStorage is blocked');\n }\n };\n\n const removeItem = (key: string) => {\n try {\n window[type].removeItem(key);\n } catch (error) {\n console.warn(\n 'use-local-storage: Failed to remove value from storage, localStorage is blocked'\n );\n }\n };\n\n return { getItem, setItem, removeItem };\n}\n\nexport type UseStorageReturnValue<T> = [\n T, // current value\n (val: T | ((prevState: T) => T)) => void, // callback to set value in storage\n () => void, // callback to remove value from storage\n];\n\nexport function createStorage<T>(type: StorageType, hookName: string) {\n const eventName = type === 'localStorage' ? 'mantine-local-storage' : 'mantine-session-storage';\n const { getItem, setItem, removeItem } = createStorageHandler(type);\n\n return function useStorage({\n key,\n defaultValue,\n getInitialValueInEffect = true,\n sync = true,\n deserialize = deserializeJSON,\n serialize = (value: T) => serializeJSON(value, hookName),\n }: UseStorageOptions<T>): UseStorageReturnValue<T> {\n const readStorageValue = useCallback(\n (skipStorage?: boolean): T => {\n let storageBlockedOrSkipped;\n\n try {\n storageBlockedOrSkipped =\n typeof window === 'undefined' ||\n !(type in window) ||\n window[type] === null ||\n !!skipStorage;\n } catch (_e) {\n storageBlockedOrSkipped = true;\n }\n\n if (storageBlockedOrSkipped) {\n return defaultValue as T;\n }\n\n const storageValue = getItem(key);\n return storageValue !== null ? deserialize(storageValue) : (defaultValue as T);\n },\n [key, defaultValue]\n );\n\n const [value, setValue] = useState<T>(readStorageValue(getInitialValueInEffect));\n\n const setStorageValue = useCallback(\n (val: T | ((prevState: T) => T)) => {\n if (val instanceof Function) {\n setValue((current) => {\n const result = val(current);\n setItem(key, serialize(result));\n // Defer dispatching this event to avoid the handler being called during render.\n queueMicrotask(() => {\n window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: result } }));\n });\n return result;\n });\n } else {\n setItem(key, serialize(val));\n window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: val } }));\n setValue(val);\n }\n },\n [key]\n );\n\n const removeStorageValue = useCallback(() => {\n removeItem(key);\n setValue(defaultValue as T);\n window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: defaultValue } }));\n }, [key, defaultValue]);\n\n useWindowEvent('storage', (event) => {\n if (sync) {\n if (event.storageArea === window[type] && event.key === key) {\n setValue(deserialize(event.newValue ?? undefined));\n }\n }\n });\n\n useWindowEvent(eventName, (event) => {\n if (sync) {\n if (event.detail.key === key) {\n setValue(event.detail.value);\n }\n }\n });\n\n useEffect(() => {\n if (defaultValue !== undefined && value === undefined) {\n setStorageValue(defaultValue);\n }\n }, [defaultValue, value, setStorageValue]);\n\n useEffect(() => {\n const val = readStorageValue();\n val !== undefined && setStorageValue(val);\n }, [key]);\n\n return [value === undefined ? (defaultValue as T) : value, setStorageValue, removeStorageValue];\n };\n}\n\nexport function readValue(type: StorageType) {\n const { getItem } = createStorageHandler(type);\n\n return function read<T>({\n key,\n defaultValue,\n deserialize = deserializeJSON,\n }: UseStorageOptions<T>) {\n let storageBlockedOrSkipped;\n\n try {\n storageBlockedOrSkipped =\n typeof window === 'undefined' || !(type in window) || window[type] === null;\n } catch (_e) {\n storageBlockedOrSkipped = true;\n }\n\n if (storageBlockedOrSkipped) {\n return defaultValue as T;\n }\n\n const storageValue = getItem(key);\n return storageValue !== null ? deserialize(storageValue) : (defaultValue as T);\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"create-storage.mjs","names":[],"sources":["../../src/use-local-storage/create-storage.ts"],"sourcesContent":["/* oxlint-disable no-console */\nimport { useCallback, useEffect, useState } from 'react';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\nexport type StorageType = 'localStorage' | 'sessionStorage';\n\nexport interface UseStorageOptions<T> {\n /** Storage key */\n key: string;\n\n /** Default value that will be set if value is not found in storage */\n defaultValue?: T;\n\n /** If set to true, value will be updated in useEffect after mount. Default value is true. */\n getInitialValueInEffect?: boolean;\n\n /** Determines whether the value must be synced between browser tabs, `true` by default */\n sync?: boolean;\n\n /** Function to serialize value into string to be save in storage */\n serialize?: (value: T) => string;\n\n /** Function to deserialize string value from storage to value */\n deserialize?: (value: string | undefined) => T;\n}\n\nfunction serializeJSON<T>(value: T, hookName: string = 'use-local-storage') {\n try {\n return JSON.stringify(value);\n } catch (error) {\n throw new Error(`@mantine/hooks ${hookName}: Failed to serialize the value`);\n }\n}\n\nfunction deserializeJSON(value: string | undefined) {\n try {\n return value && JSON.parse(value);\n } catch {\n return value;\n }\n}\n\nfunction createStorageHandler(type: StorageType) {\n const getItem = (key: string) => {\n try {\n return window[type].getItem(key);\n } catch (error) {\n console.warn('use-local-storage: Failed to get value from storage, localStorage is blocked');\n return null;\n }\n };\n\n const setItem = (key: string, value: string) => {\n try {\n window[type].setItem(key, value);\n } catch (error) {\n console.warn('use-local-storage: Failed to set value to storage, localStorage is blocked');\n }\n };\n\n const removeItem = (key: string) => {\n try {\n window[type].removeItem(key);\n } catch (error) {\n console.warn(\n 'use-local-storage: Failed to remove value from storage, localStorage is blocked'\n );\n }\n };\n\n return { getItem, setItem, removeItem };\n}\n\nexport type UseStorageReturnValue<T> = [\n T, // current value\n (val: T | ((prevState: T) => T)) => void, // callback to set value in storage\n () => void, // callback to remove value from storage\n];\n\nexport function createStorage<T>(type: StorageType, hookName: string) {\n const eventName = type === 'localStorage' ? 'mantine-local-storage' : 'mantine-session-storage';\n const { getItem, setItem, removeItem } = createStorageHandler(type);\n\n return function useStorage({\n key,\n defaultValue,\n getInitialValueInEffect = true,\n sync = true,\n deserialize = deserializeJSON,\n serialize = (value: T) => serializeJSON(value, hookName),\n }: UseStorageOptions<T>): UseStorageReturnValue<T> {\n const readStorageValue = useCallback(\n (skipStorage?: boolean): T => {\n let storageBlockedOrSkipped;\n\n try {\n storageBlockedOrSkipped =\n typeof window === 'undefined' ||\n !(type in window) ||\n window[type] === null ||\n !!skipStorage;\n } catch (_e) {\n storageBlockedOrSkipped = true;\n }\n\n if (storageBlockedOrSkipped) {\n return defaultValue as T;\n }\n\n const storageValue = getItem(key);\n return storageValue !== null ? deserialize(storageValue) : (defaultValue as T);\n },\n [key, defaultValue]\n );\n\n const [value, setValue] = useState<T>(readStorageValue(getInitialValueInEffect));\n\n const setStorageValue = useCallback(\n (val: T | ((prevState: T) => T)) => {\n if (val instanceof Function) {\n setValue((current) => {\n const result = val(current);\n setItem(key, serialize(result));\n // Defer dispatching this event to avoid the handler being called during render.\n queueMicrotask(() => {\n window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: result } }));\n });\n return result;\n });\n } else {\n setItem(key, serialize(val));\n window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: val } }));\n setValue(val);\n }\n },\n [key]\n );\n\n const removeStorageValue = useCallback(() => {\n removeItem(key);\n setValue(defaultValue as T);\n window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: defaultValue } }));\n }, [key, defaultValue]);\n\n useWindowEvent('storage', (event) => {\n if (sync) {\n if (event.storageArea === window[type] && event.key === key) {\n setValue(deserialize(event.newValue ?? undefined));\n }\n }\n });\n\n useWindowEvent(eventName, (event) => {\n if (sync) {\n if (event.detail.key === key) {\n setValue(event.detail.value);\n }\n }\n });\n\n useEffect(() => {\n if (defaultValue !== undefined && value === undefined) {\n setStorageValue(defaultValue);\n }\n }, [defaultValue, value, setStorageValue]);\n\n useEffect(() => {\n const val = readStorageValue();\n val !== undefined && setStorageValue(val);\n }, [key]);\n\n return [value === undefined ? (defaultValue as T) : value, setStorageValue, removeStorageValue];\n };\n}\n\nexport function readValue(type: StorageType) {\n const { getItem } = createStorageHandler(type);\n\n return function read<T>({\n key,\n defaultValue,\n deserialize = deserializeJSON,\n }: UseStorageOptions<T>) {\n let storageBlockedOrSkipped;\n\n try {\n storageBlockedOrSkipped =\n typeof window === 'undefined' || !(type in window) || window[type] === null;\n } catch (_e) {\n storageBlockedOrSkipped = true;\n }\n\n if (storageBlockedOrSkipped) {\n return defaultValue as T;\n }\n\n const storageValue = getItem(key);\n return storageValue !== null ? deserialize(storageValue) : (defaultValue as T);\n };\n}\n"],"mappings":"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"}
@@ -10,6 +10,7 @@ function useLongPress(onLongPress, options = {}) {
10
10
  const timeout = useRef(-1);
11
11
  const startPosition = useRef(null);
12
12
  useEffect(() => () => window.clearTimeout(timeout.current), []);
13
+ const eventsKey = events.join(",");
13
14
  return useMemo(() => {
14
15
  if (typeof onLongPress !== "function") return {};
15
16
  const moveEnabled = cancelOnMove !== false;
@@ -68,7 +69,7 @@ function useLongPress(onLongPress, options = {}) {
68
69
  onFinish,
69
70
  onStart,
70
71
  cancelOnMove,
71
- events.join(",")
72
+ eventsKey
72
73
  ]);
73
74
  }
74
75
  function getEventPosition(event) {
@@ -1 +1 @@
1
- {"version":3,"file":"use-long-press.mjs","names":[],"sources":["../../src/use-long-press/use-long-press.ts"],"sourcesContent":["import React, { useEffect, useMemo, useRef } from 'react';\n\nexport type UseLongPressEvent = 'mouse' | 'touch';\n\nexport interface UseLongPressOptions {\n /** Time in milliseconds to trigger the long press, default is 400ms */\n threshold?: number;\n\n /** Input types that can trigger the long press, `['mouse', 'touch']` by default */\n events?: UseLongPressEvent[];\n\n /** If set, the long press is canceled when the pointer moves further than the given distance in px from the start position. `true` uses a 10px threshold, a number sets a custom threshold. `false` by default */\n cancelOnMove?: boolean | number;\n\n /** Callback triggered when the long press starts */\n onStart?: (event: React.MouseEvent | React.TouchEvent) => void;\n\n /** Callback triggered when the long press finishes */\n onFinish?: (event: React.MouseEvent | React.TouchEvent) => void;\n\n /** Callback triggered when the long press is canceled */\n onCancel?: (event: React.MouseEvent | React.TouchEvent) => void;\n}\n\nexport interface UseLongPressReturnValue {\n onMouseDown?: (event: React.MouseEvent) => void;\n onMouseUp?: (event: React.MouseEvent) => void;\n onMouseLeave?: (event: React.MouseEvent) => void;\n onMouseMove?: (event: React.MouseEvent) => void;\n onTouchStart?: (event: React.TouchEvent) => void;\n onTouchEnd?: (event: React.TouchEvent) => void;\n onTouchCancel?: (event: React.TouchEvent) => void;\n onTouchMove?: (event: React.TouchEvent) => void;\n}\n\nconst DEFAULT_EVENTS: UseLongPressEvent[] = ['mouse', 'touch'];\nconst DEFAULT_MOVE_THRESHOLD = 10;\n\nexport function useLongPress(\n onLongPress: (event: React.MouseEvent | React.TouchEvent) => void,\n options: UseLongPressOptions = {}\n): UseLongPressReturnValue {\n const {\n threshold = 400,\n events = DEFAULT_EVENTS,\n cancelOnMove = false,\n onStart,\n onFinish,\n onCancel,\n } = options;\n const isLongPressActive = useRef(false);\n const isPressed = useRef(false);\n const timeout = useRef<number>(-1);\n const startPosition = useRef<{ x: number; y: number } | null>(null);\n\n useEffect(() => () => window.clearTimeout(timeout.current), []);\n\n const eventsKey = events.join(',');\n\n return useMemo(() => {\n if (typeof onLongPress !== 'function') {\n return {} as UseLongPressReturnValue;\n }\n\n const moveEnabled = cancelOnMove !== false;\n const moveThreshold =\n cancelOnMove === true ? DEFAULT_MOVE_THRESHOLD : cancelOnMove === false ? 0 : cancelOnMove;\n\n const start = (event: React.MouseEvent | React.TouchEvent) => {\n if (!isMouseEvent(event) && !isTouchEvent(event)) {\n return;\n }\n\n if (onStart) {\n onStart(event);\n }\n\n startPosition.current = getEventPosition(event);\n isPressed.current = true;\n timeout.current = window.setTimeout(() => {\n onLongPress(event);\n isLongPressActive.current = true;\n }, threshold);\n };\n\n const cancel = (event: React.MouseEvent | React.TouchEvent) => {\n if (!isMouseEvent(event) && !isTouchEvent(event)) {\n return;\n }\n\n if (isLongPressActive.current) {\n if (onFinish) {\n onFinish(event);\n }\n } else if (isPressed.current) {\n if (onCancel) {\n onCancel(event);\n }\n }\n\n isLongPressActive.current = false;\n isPressed.current = false;\n startPosition.current = null;\n\n if (timeout.current !== -1) {\n window.clearTimeout(timeout.current);\n timeout.current = -1;\n }\n };\n\n const move = (event: React.MouseEvent | React.TouchEvent) => {\n if (!moveEnabled || !isPressed.current || isLongPressActive.current) {\n return;\n }\n\n const position = getEventPosition(event);\n if (!position || !startPosition.current) {\n return;\n }\n\n const dx = position.x - startPosition.current.x;\n const dy = position.y - startPosition.current.y;\n\n if (Math.sqrt(dx * dx + dy * dy) > moveThreshold) {\n cancel(event);\n }\n };\n\n const handlers: UseLongPressReturnValue = {};\n\n if (events.includes('mouse')) {\n handlers.onMouseDown = start;\n handlers.onMouseUp = cancel;\n handlers.onMouseLeave = cancel;\n if (moveEnabled) {\n handlers.onMouseMove = move;\n }\n }\n\n if (events.includes('touch')) {\n handlers.onTouchStart = start;\n handlers.onTouchEnd = cancel;\n handlers.onTouchCancel = cancel;\n if (moveEnabled) {\n handlers.onTouchMove = move;\n }\n }\n\n return handlers;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [onLongPress, threshold, onCancel, onFinish, onStart, cancelOnMove, eventsKey]);\n}\n\nfunction getEventPosition(\n event: React.MouseEvent | React.TouchEvent\n): { x: number; y: number } | null {\n if (isTouchEvent(event)) {\n const touch = event.touches[0] ?? event.changedTouches[0];\n return touch ? { x: touch.clientX, y: touch.clientY } : null;\n }\n\n return { x: event.clientX, y: event.clientY };\n}\n\nfunction isTouchEvent(event: React.MouseEvent | React.TouchEvent): event is React.TouchEvent {\n return window.TouchEvent\n ? event.nativeEvent instanceof TouchEvent\n : 'touches' in event.nativeEvent;\n}\n\nfunction isMouseEvent(event: React.MouseEvent | React.TouchEvent): event is React.MouseEvent {\n return event.nativeEvent instanceof MouseEvent;\n}\n\nexport namespace useLongPress {\n export type Options = UseLongPressOptions;\n export type ReturnValue = UseLongPressReturnValue;\n}\n"],"mappings":";;;AAmCA,MAAM,iBAAsC,CAAC,SAAS,OAAO;AAC7D,MAAM,yBAAyB;AAE/B,SAAgB,aACd,aACA,UAA+B,CAAC,GACP;CACzB,MAAM,EACJ,YAAY,KACZ,SAAS,gBACT,eAAe,OACf,SACA,UACA,aACE;CACJ,MAAM,oBAAoB,OAAO,KAAK;CACtC,MAAM,YAAY,OAAO,KAAK;CAC9B,MAAM,UAAU,OAAe,EAAE;CACjC,MAAM,gBAAgB,OAAwC,IAAI;CAElE,sBAAsB,OAAO,aAAa,QAAQ,OAAO,GAAG,CAAC,CAAC;CAI9D,OAAO,cAAc;EACnB,IAAI,OAAO,gBAAgB,YACzB,OAAO,CAAC;EAGV,MAAM,cAAc,iBAAiB;EACrC,MAAM,gBACJ,iBAAiB,OAAO,yBAAyB,iBAAiB,QAAQ,IAAI;EAEhF,MAAM,SAAS,UAA+C;GAC5D,IAAI,CAAC,aAAa,KAAK,KAAK,CAAC,aAAa,KAAK,GAC7C;GAGF,IAAI,SACF,QAAQ,KAAK;GAGf,cAAc,UAAU,iBAAiB,KAAK;GAC9C,UAAU,UAAU;GACpB,QAAQ,UAAU,OAAO,iBAAiB;IACxC,YAAY,KAAK;IACjB,kBAAkB,UAAU;GAC9B,GAAG,SAAS;EACd;EAEA,MAAM,UAAU,UAA+C;GAC7D,IAAI,CAAC,aAAa,KAAK,KAAK,CAAC,aAAa,KAAK,GAC7C;GAGF,IAAI,kBAAkB;QAChB,UACF,SAAS,KAAK;GAAA,OAEX,IAAI,UAAU;QACf,UACF,SAAS,KAAK;GAAA;GAIlB,kBAAkB,UAAU;GAC5B,UAAU,UAAU;GACpB,cAAc,UAAU;GAExB,IAAI,QAAQ,YAAY,IAAI;IAC1B,OAAO,aAAa,QAAQ,OAAO;IACnC,QAAQ,UAAU;GACpB;EACF;EAEA,MAAM,QAAQ,UAA+C;GAC3D,IAAI,CAAC,eAAe,CAAC,UAAU,WAAW,kBAAkB,SAC1D;GAGF,MAAM,WAAW,iBAAiB,KAAK;GACvC,IAAI,CAAC,YAAY,CAAC,cAAc,SAC9B;GAGF,MAAM,KAAK,SAAS,IAAI,cAAc,QAAQ;GAC9C,MAAM,KAAK,SAAS,IAAI,cAAc,QAAQ;GAE9C,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,IAAI,eACjC,OAAO,KAAK;EAEhB;EAEA,MAAM,WAAoC,CAAC;EAE3C,IAAI,OAAO,SAAS,OAAO,GAAG;GAC5B,SAAS,cAAc;GACvB,SAAS,YAAY;GACrB,SAAS,eAAe;GACxB,IAAI,aACF,SAAS,cAAc;EAE3B;EAEA,IAAI,OAAO,SAAS,OAAO,GAAG;GAC5B,SAAS,eAAe;GACxB,SAAS,aAAa;GACtB,SAAS,gBAAgB;GACzB,IAAI,aACF,SAAS,cAAc;EAE3B;EAEA,OAAO;CAET,GAAG;EAAC;EAAa;EAAW;EAAU;EAAU;EAAS;EA7FvC,OAAO,KAAK,GA6FiD;CAAC,CAAC;AACnF;AAEA,SAAS,iBACP,OACiC;CACjC,IAAI,aAAa,KAAK,GAAG;EACvB,MAAM,QAAQ,MAAM,QAAQ,MAAM,MAAM,eAAe;EACvD,OAAO,QAAQ;GAAE,GAAG,MAAM;GAAS,GAAG,MAAM;EAAQ,IAAI;CAC1D;CAEA,OAAO;EAAE,GAAG,MAAM;EAAS,GAAG,MAAM;CAAQ;AAC9C;AAEA,SAAS,aAAa,OAAuE;CAC3F,OAAO,OAAO,aACV,MAAM,uBAAuB,aAC7B,aAAa,MAAM;AACzB;AAEA,SAAS,aAAa,OAAuE;CAC3F,OAAO,MAAM,uBAAuB;AACtC"}
1
+ {"version":3,"file":"use-long-press.mjs","names":[],"sources":["../../src/use-long-press/use-long-press.ts"],"sourcesContent":["import React, { useEffect, useMemo, useRef } from 'react';\n\nexport type UseLongPressEvent = 'mouse' | 'touch';\n\nexport interface UseLongPressOptions {\n /** Time in milliseconds to trigger the long press, default is 400ms */\n threshold?: number;\n\n /** Input types that can trigger the long press, `['mouse', 'touch']` by default */\n events?: UseLongPressEvent[];\n\n /** If set, the long press is canceled when the pointer moves further than the given distance in px from the start position. `true` uses a 10px threshold, a number sets a custom threshold. `false` by default */\n cancelOnMove?: boolean | number;\n\n /** Callback triggered when the long press starts */\n onStart?: (event: React.MouseEvent | React.TouchEvent) => void;\n\n /** Callback triggered when the long press finishes */\n onFinish?: (event: React.MouseEvent | React.TouchEvent) => void;\n\n /** Callback triggered when the long press is canceled */\n onCancel?: (event: React.MouseEvent | React.TouchEvent) => void;\n}\n\nexport interface UseLongPressReturnValue {\n onMouseDown?: (event: React.MouseEvent) => void;\n onMouseUp?: (event: React.MouseEvent) => void;\n onMouseLeave?: (event: React.MouseEvent) => void;\n onMouseMove?: (event: React.MouseEvent) => void;\n onTouchStart?: (event: React.TouchEvent) => void;\n onTouchEnd?: (event: React.TouchEvent) => void;\n onTouchCancel?: (event: React.TouchEvent) => void;\n onTouchMove?: (event: React.TouchEvent) => void;\n}\n\nconst DEFAULT_EVENTS: UseLongPressEvent[] = ['mouse', 'touch'];\nconst DEFAULT_MOVE_THRESHOLD = 10;\n\nexport function useLongPress(\n onLongPress: (event: React.MouseEvent | React.TouchEvent) => void,\n options: UseLongPressOptions = {}\n): UseLongPressReturnValue {\n const {\n threshold = 400,\n events = DEFAULT_EVENTS,\n cancelOnMove = false,\n onStart,\n onFinish,\n onCancel,\n } = options;\n const isLongPressActive = useRef(false);\n const isPressed = useRef(false);\n const timeout = useRef<number>(-1);\n const startPosition = useRef<{ x: number; y: number } | null>(null);\n\n useEffect(() => () => window.clearTimeout(timeout.current), []);\n\n const eventsKey = events.join(',');\n\n return useMemo(() => {\n if (typeof onLongPress !== 'function') {\n return {} as UseLongPressReturnValue;\n }\n\n const moveEnabled = cancelOnMove !== false;\n const moveThreshold =\n cancelOnMove === true ? DEFAULT_MOVE_THRESHOLD : cancelOnMove === false ? 0 : cancelOnMove;\n\n const start = (event: React.MouseEvent | React.TouchEvent) => {\n if (!isMouseEvent(event) && !isTouchEvent(event)) {\n return;\n }\n\n if (onStart) {\n onStart(event);\n }\n\n startPosition.current = getEventPosition(event);\n isPressed.current = true;\n timeout.current = window.setTimeout(() => {\n onLongPress(event);\n isLongPressActive.current = true;\n }, threshold);\n };\n\n const cancel = (event: React.MouseEvent | React.TouchEvent) => {\n if (!isMouseEvent(event) && !isTouchEvent(event)) {\n return;\n }\n\n if (isLongPressActive.current) {\n if (onFinish) {\n onFinish(event);\n }\n } else if (isPressed.current) {\n if (onCancel) {\n onCancel(event);\n }\n }\n\n isLongPressActive.current = false;\n isPressed.current = false;\n startPosition.current = null;\n\n if (timeout.current !== -1) {\n window.clearTimeout(timeout.current);\n timeout.current = -1;\n }\n };\n\n const move = (event: React.MouseEvent | React.TouchEvent) => {\n if (!moveEnabled || !isPressed.current || isLongPressActive.current) {\n return;\n }\n\n const position = getEventPosition(event);\n if (!position || !startPosition.current) {\n return;\n }\n\n const dx = position.x - startPosition.current.x;\n const dy = position.y - startPosition.current.y;\n\n if (Math.sqrt(dx * dx + dy * dy) > moveThreshold) {\n cancel(event);\n }\n };\n\n const handlers: UseLongPressReturnValue = {};\n\n if (events.includes('mouse')) {\n handlers.onMouseDown = start;\n handlers.onMouseUp = cancel;\n handlers.onMouseLeave = cancel;\n if (moveEnabled) {\n handlers.onMouseMove = move;\n }\n }\n\n if (events.includes('touch')) {\n handlers.onTouchStart = start;\n handlers.onTouchEnd = cancel;\n handlers.onTouchCancel = cancel;\n if (moveEnabled) {\n handlers.onTouchMove = move;\n }\n }\n\n return handlers;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [onLongPress, threshold, onCancel, onFinish, onStart, cancelOnMove, eventsKey]);\n}\n\nfunction getEventPosition(\n event: React.MouseEvent | React.TouchEvent\n): { x: number; y: number } | null {\n if (isTouchEvent(event)) {\n const touch = event.touches[0] ?? event.changedTouches[0];\n return touch ? { x: touch.clientX, y: touch.clientY } : null;\n }\n\n return { x: event.clientX, y: event.clientY };\n}\n\nfunction isTouchEvent(event: React.MouseEvent | React.TouchEvent): event is React.TouchEvent {\n return window.TouchEvent\n ? event.nativeEvent instanceof TouchEvent\n : 'touches' in event.nativeEvent;\n}\n\nfunction isMouseEvent(event: React.MouseEvent | React.TouchEvent): event is React.MouseEvent {\n return event.nativeEvent instanceof MouseEvent;\n}\n\nexport namespace useLongPress {\n export type Options = UseLongPressOptions;\n export type ReturnValue = UseLongPressReturnValue;\n}\n"],"mappings":";;;AAmCA,MAAM,iBAAsC,CAAC,SAAS,OAAO;AAC7D,MAAM,yBAAyB;AAE/B,SAAgB,aACd,aACA,UAA+B,CAAC,GACP;CACzB,MAAM,EACJ,YAAY,KACZ,SAAS,gBACT,eAAe,OACf,SACA,UACA,aACE;CACJ,MAAM,oBAAoB,OAAO,KAAK;CACtC,MAAM,YAAY,OAAO,KAAK;CAC9B,MAAM,UAAU,OAAe,EAAE;CACjC,MAAM,gBAAgB,OAAwC,IAAI;CAElE,sBAAsB,OAAO,aAAa,QAAQ,OAAO,GAAG,CAAC,CAAC;CAE9D,MAAM,YAAY,OAAO,KAAK,GAAG;CAEjC,OAAO,cAAc;EACnB,IAAI,OAAO,gBAAgB,YACzB,OAAO,CAAC;EAGV,MAAM,cAAc,iBAAiB;EACrC,MAAM,gBACJ,iBAAiB,OAAO,yBAAyB,iBAAiB,QAAQ,IAAI;EAEhF,MAAM,SAAS,UAA+C;GAC5D,IAAI,CAAC,aAAa,KAAK,KAAK,CAAC,aAAa,KAAK,GAC7C;GAGF,IAAI,SACF,QAAQ,KAAK;GAGf,cAAc,UAAU,iBAAiB,KAAK;GAC9C,UAAU,UAAU;GACpB,QAAQ,UAAU,OAAO,iBAAiB;IACxC,YAAY,KAAK;IACjB,kBAAkB,UAAU;GAC9B,GAAG,SAAS;EACd;EAEA,MAAM,UAAU,UAA+C;GAC7D,IAAI,CAAC,aAAa,KAAK,KAAK,CAAC,aAAa,KAAK,GAC7C;GAGF,IAAI,kBAAkB,SAChB;QAAA,UACF,SAAS,KAAK;GAAA,OAEX,IAAI,UAAU,SACf;QAAA,UACF,SAAS,KAAK;GAAA;GAIlB,kBAAkB,UAAU;GAC5B,UAAU,UAAU;GACpB,cAAc,UAAU;GAExB,IAAI,QAAQ,YAAY,IAAI;IAC1B,OAAO,aAAa,QAAQ,OAAO;IACnC,QAAQ,UAAU;GACpB;EACF;EAEA,MAAM,QAAQ,UAA+C;GAC3D,IAAI,CAAC,eAAe,CAAC,UAAU,WAAW,kBAAkB,SAC1D;GAGF,MAAM,WAAW,iBAAiB,KAAK;GACvC,IAAI,CAAC,YAAY,CAAC,cAAc,SAC9B;GAGF,MAAM,KAAK,SAAS,IAAI,cAAc,QAAQ;GAC9C,MAAM,KAAK,SAAS,IAAI,cAAc,QAAQ;GAE9C,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,IAAI,eACjC,OAAO,KAAK;EAEhB;EAEA,MAAM,WAAoC,CAAC;EAE3C,IAAI,OAAO,SAAS,OAAO,GAAG;GAC5B,SAAS,cAAc;GACvB,SAAS,YAAY;GACrB,SAAS,eAAe;GACxB,IAAI,aACF,SAAS,cAAc;EAE3B;EAEA,IAAI,OAAO,SAAS,OAAO,GAAG;GAC5B,SAAS,eAAe;GACxB,SAAS,aAAa;GACtB,SAAS,gBAAgB;GACzB,IAAI,aACF,SAAS,cAAc;EAE3B;EAEA,OAAO;CAET,GAAG;EAAC;EAAa;EAAW;EAAU;EAAU;EAAS;EAAc;CAAS,CAAC;AACnF;AAEA,SAAS,iBACP,OACiC;CACjC,IAAI,aAAa,KAAK,GAAG;EACvB,MAAM,QAAQ,MAAM,QAAQ,MAAM,MAAM,eAAe;EACvD,OAAO,QAAQ;GAAE,GAAG,MAAM;GAAS,GAAG,MAAM;EAAQ,IAAI;CAC1D;CAEA,OAAO;EAAE,GAAG,MAAM;EAAS,GAAG,MAAM;CAAQ;AAC9C;AAEA,SAAS,aAAa,OAAuE;CAC3F,OAAO,OAAO,aACV,MAAM,uBAAuB,aAC7B,aAAa,MAAM;AACzB;AAEA,SAAS,aAAa,OAAuE;CAC3F,OAAO,MAAM,uBAAuB;AACtC"}
@@ -589,13 +589,15 @@ function useMask(options) {
589
589
  setMaskedValue("");
590
590
  setRawValue("");
591
591
  wasCompleteRef.current = false;
592
- if (input) if (opts.alwaysShowMask) {
593
- const { slots, slotChar } = getResolvedOptions(opts, "");
594
- const display = buildDisplayValue("", slots, slotChar, true);
595
- input.value = display;
596
- displayValueRef.current = display;
597
- setMaskedValue(display);
598
- } else input.value = "";
592
+ if (input) {
593
+ if (opts.alwaysShowMask) {
594
+ const { slots, slotChar } = getResolvedOptions(opts, "");
595
+ const display = buildDisplayValue("", slots, slotChar, true);
596
+ input.value = display;
597
+ displayValueRef.current = display;
598
+ setMaskedValue(display);
599
+ } else input.value = "";
600
+ }
599
601
  if (opts.onChangeRaw) opts.onChangeRaw("", "");
600
602
  }, [])
601
603
  };