@mantine/hooks 9.0.2 → 9.1.0

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 (166) hide show
  1. package/cjs/index.cjs +8 -0
  2. package/cjs/use-click-outside/use-click-outside.cjs +11 -8
  3. package/cjs/use-click-outside/use-click-outside.cjs.map +1 -1
  4. package/cjs/use-clipboard/use-clipboard.cjs +13 -6
  5. package/cjs/use-clipboard/use-clipboard.cjs.map +1 -1
  6. package/cjs/use-collapse/use-collapse.cjs +1 -1
  7. package/cjs/use-collapse/use-collapse.cjs.map +1 -1
  8. package/cjs/use-collapse/use-horizontal-collapse.cjs +4 -3
  9. package/cjs/use-collapse/use-horizontal-collapse.cjs.map +1 -1
  10. package/cjs/use-counter/use-counter.cjs +12 -3
  11. package/cjs/use-counter/use-counter.cjs.map +1 -1
  12. package/cjs/use-debounced-callback/use-debounced-callback.cjs +28 -4
  13. package/cjs/use-debounced-callback/use-debounced-callback.cjs.map +1 -1
  14. package/cjs/use-debounced-state/use-debounced-state.cjs +1 -1
  15. package/cjs/use-debounced-state/use-debounced-state.cjs.map +1 -1
  16. package/cjs/use-debounced-value/use-debounced-value.cjs +22 -2
  17. package/cjs/use-debounced-value/use-debounced-value.cjs.map +1 -1
  18. package/cjs/use-event-listener/use-event-listener.cjs.map +1 -1
  19. package/cjs/use-favicon/use-favicon.cjs +3 -1
  20. package/cjs/use-favicon/use-favicon.cjs.map +1 -1
  21. package/cjs/use-fetch/use-fetch.cjs +7 -4
  22. package/cjs/use-fetch/use-fetch.cjs.map +1 -1
  23. package/cjs/use-file-dialog/use-file-dialog.cjs +1 -0
  24. package/cjs/use-file-dialog/use-file-dialog.cjs.map +1 -1
  25. package/cjs/use-floating-window/use-floating-window.cjs +33 -36
  26. package/cjs/use-floating-window/use-floating-window.cjs.map +1 -1
  27. package/cjs/use-focus-trap/use-focus-trap.cjs +12 -9
  28. package/cjs/use-focus-trap/use-focus-trap.cjs.map +1 -1
  29. package/cjs/use-fullscreen/use-fullscreen.cjs +3 -1
  30. package/cjs/use-fullscreen/use-fullscreen.cjs.map +1 -1
  31. package/cjs/use-headroom/use-headroom.cjs +4 -1
  32. package/cjs/use-headroom/use-headroom.cjs.map +1 -1
  33. package/cjs/use-hotkeys/parse-hotkey.cjs +1 -2
  34. package/cjs/use-hotkeys/parse-hotkey.cjs.map +1 -1
  35. package/cjs/use-hover/use-hover.cjs +1 -0
  36. package/cjs/use-hover/use-hover.cjs.map +1 -1
  37. package/cjs/use-in-viewport/use-in-viewport.cjs +11 -7
  38. package/cjs/use-in-viewport/use-in-viewport.cjs.map +1 -1
  39. package/cjs/use-interval/use-interval.cjs +15 -6
  40. package/cjs/use-interval/use-interval.cjs.map +1 -1
  41. package/cjs/use-local-storage/create-storage.cjs +1 -1
  42. package/cjs/use-local-storage/create-storage.cjs.map +1 -1
  43. package/cjs/use-long-press/use-long-press.cjs +6 -2
  44. package/cjs/use-long-press/use-long-press.cjs.map +1 -1
  45. package/cjs/use-mask/use-mask.cjs +457 -0
  46. package/cjs/use-mask/use-mask.cjs.map +1 -0
  47. package/cjs/use-mouse/use-mouse.cjs +2 -2
  48. package/cjs/use-mouse/use-mouse.cjs.map +1 -1
  49. package/cjs/use-move/use-move.cjs +8 -0
  50. package/cjs/use-move/use-move.cjs.map +1 -1
  51. package/cjs/use-orientation/use-orientation.cjs +8 -2
  52. package/cjs/use-orientation/use-orientation.cjs.map +1 -1
  53. package/cjs/use-os/use-os.cjs +1 -1
  54. package/cjs/use-os/use-os.cjs.map +1 -1
  55. package/cjs/use-radial-move/use-radial-move.cjs +4 -4
  56. package/cjs/use-radial-move/use-radial-move.cjs.map +1 -1
  57. package/cjs/use-roving-index/use-roving-index.cjs +200 -0
  58. package/cjs/use-roving-index/use-roving-index.cjs.map +1 -0
  59. package/cjs/use-scroll-direction/use-scroll-direction.cjs +7 -7
  60. package/cjs/use-scroll-direction/use-scroll-direction.cjs.map +1 -1
  61. package/cjs/use-scroll-into-view/use-scroll-into-view.cjs +14 -4
  62. package/cjs/use-scroll-into-view/use-scroll-into-view.cjs.map +1 -1
  63. package/cjs/use-scroll-spy/use-scroll-spy.cjs +7 -3
  64. package/cjs/use-scroll-spy/use-scroll-spy.cjs.map +1 -1
  65. package/cjs/use-scroller/use-scroller.cjs +3 -3
  66. package/cjs/use-scroller/use-scroller.cjs.map +1 -1
  67. package/cjs/use-set/use-set.cjs +6 -1
  68. package/cjs/use-set/use-set.cjs.map +1 -1
  69. package/cjs/use-throttled-callback/use-throttled-callback.cjs +3 -1
  70. package/cjs/use-throttled-callback/use-throttled-callback.cjs.map +1 -1
  71. package/cjs/use-timeout/use-timeout.cjs +3 -1
  72. package/cjs/use-timeout/use-timeout.cjs.map +1 -1
  73. package/cjs/use-viewport-size/use-viewport-size.cjs +3 -3
  74. package/cjs/use-viewport-size/use-viewport-size.cjs.map +1 -1
  75. package/cjs/use-window-scroll/use-window-scroll.cjs +2 -2
  76. package/cjs/use-window-scroll/use-window-scroll.cjs.map +1 -1
  77. package/esm/index.mjs +3 -1
  78. package/esm/use-click-outside/use-click-outside.mjs +11 -8
  79. package/esm/use-click-outside/use-click-outside.mjs.map +1 -1
  80. package/esm/use-clipboard/use-clipboard.mjs +14 -7
  81. package/esm/use-clipboard/use-clipboard.mjs.map +1 -1
  82. package/esm/use-collapse/use-collapse.mjs +1 -1
  83. package/esm/use-collapse/use-collapse.mjs.map +1 -1
  84. package/esm/use-collapse/use-horizontal-collapse.mjs +5 -4
  85. package/esm/use-collapse/use-horizontal-collapse.mjs.map +1 -1
  86. package/esm/use-counter/use-counter.mjs +12 -3
  87. package/esm/use-counter/use-counter.mjs.map +1 -1
  88. package/esm/use-debounced-callback/use-debounced-callback.mjs +28 -4
  89. package/esm/use-debounced-callback/use-debounced-callback.mjs.map +1 -1
  90. package/esm/use-debounced-state/use-debounced-state.mjs +1 -1
  91. package/esm/use-debounced-state/use-debounced-state.mjs.map +1 -1
  92. package/esm/use-debounced-value/use-debounced-value.mjs +22 -2
  93. package/esm/use-debounced-value/use-debounced-value.mjs.map +1 -1
  94. package/esm/use-event-listener/use-event-listener.mjs.map +1 -1
  95. package/esm/use-favicon/use-favicon.mjs +3 -1
  96. package/esm/use-favicon/use-favicon.mjs.map +1 -1
  97. package/esm/use-fetch/use-fetch.mjs +7 -4
  98. package/esm/use-fetch/use-fetch.mjs.map +1 -1
  99. package/esm/use-file-dialog/use-file-dialog.mjs +1 -0
  100. package/esm/use-file-dialog/use-file-dialog.mjs.map +1 -1
  101. package/esm/use-floating-window/use-floating-window.mjs +33 -36
  102. package/esm/use-floating-window/use-floating-window.mjs.map +1 -1
  103. package/esm/use-focus-trap/use-focus-trap.mjs +12 -9
  104. package/esm/use-focus-trap/use-focus-trap.mjs.map +1 -1
  105. package/esm/use-fullscreen/use-fullscreen.mjs +3 -1
  106. package/esm/use-fullscreen/use-fullscreen.mjs.map +1 -1
  107. package/esm/use-headroom/use-headroom.mjs +4 -1
  108. package/esm/use-headroom/use-headroom.mjs.map +1 -1
  109. package/esm/use-hotkeys/parse-hotkey.mjs +1 -2
  110. package/esm/use-hotkeys/parse-hotkey.mjs.map +1 -1
  111. package/esm/use-hover/use-hover.mjs +1 -0
  112. package/esm/use-hover/use-hover.mjs.map +1 -1
  113. package/esm/use-in-viewport/use-in-viewport.mjs +11 -7
  114. package/esm/use-in-viewport/use-in-viewport.mjs.map +1 -1
  115. package/esm/use-interval/use-interval.mjs +15 -6
  116. package/esm/use-interval/use-interval.mjs.map +1 -1
  117. package/esm/use-local-storage/create-storage.mjs +1 -1
  118. package/esm/use-local-storage/create-storage.mjs.map +1 -1
  119. package/esm/use-long-press/use-long-press.mjs +6 -2
  120. package/esm/use-long-press/use-long-press.mjs.map +1 -1
  121. package/esm/use-mask/use-mask.mjs +453 -0
  122. package/esm/use-mask/use-mask.mjs.map +1 -0
  123. package/esm/use-mouse/use-mouse.mjs +2 -2
  124. package/esm/use-mouse/use-mouse.mjs.map +1 -1
  125. package/esm/use-move/use-move.mjs +8 -0
  126. package/esm/use-move/use-move.mjs.map +1 -1
  127. package/esm/use-orientation/use-orientation.mjs +8 -2
  128. package/esm/use-orientation/use-orientation.mjs.map +1 -1
  129. package/esm/use-os/use-os.mjs +1 -1
  130. package/esm/use-os/use-os.mjs.map +1 -1
  131. package/esm/use-radial-move/use-radial-move.mjs +5 -5
  132. package/esm/use-radial-move/use-radial-move.mjs.map +1 -1
  133. package/esm/use-roving-index/use-roving-index.mjs +200 -0
  134. package/esm/use-roving-index/use-roving-index.mjs.map +1 -0
  135. package/esm/use-scroll-direction/use-scroll-direction.mjs +7 -7
  136. package/esm/use-scroll-direction/use-scroll-direction.mjs.map +1 -1
  137. package/esm/use-scroll-into-view/use-scroll-into-view.mjs +15 -5
  138. package/esm/use-scroll-into-view/use-scroll-into-view.mjs.map +1 -1
  139. package/esm/use-scroll-spy/use-scroll-spy.mjs +8 -4
  140. package/esm/use-scroll-spy/use-scroll-spy.mjs.map +1 -1
  141. package/esm/use-scroller/use-scroller.mjs +3 -3
  142. package/esm/use-scroller/use-scroller.mjs.map +1 -1
  143. package/esm/use-set/use-set.mjs +6 -1
  144. package/esm/use-set/use-set.mjs.map +1 -1
  145. package/esm/use-throttled-callback/use-throttled-callback.mjs +3 -1
  146. package/esm/use-throttled-callback/use-throttled-callback.mjs.map +1 -1
  147. package/esm/use-timeout/use-timeout.mjs +3 -1
  148. package/esm/use-timeout/use-timeout.mjs.map +1 -1
  149. package/esm/use-viewport-size/use-viewport-size.mjs +3 -3
  150. package/esm/use-viewport-size/use-viewport-size.mjs.map +1 -1
  151. package/esm/use-window-scroll/use-window-scroll.mjs +2 -2
  152. package/esm/use-window-scroll/use-window-scroll.mjs.map +1 -1
  153. package/lib/index.d.mts +5 -1
  154. package/lib/index.d.ts +5 -1
  155. package/lib/use-click-outside/use-click-outside.d.ts +1 -1
  156. package/lib/use-collapse/use-horizontal-collapse.d.ts +5 -0
  157. package/lib/use-counter/use-counter.d.ts +1 -0
  158. package/lib/use-debounced-callback/use-debounced-callback.d.ts +4 -0
  159. package/lib/use-debounced-value/use-debounced-value.d.ts +6 -1
  160. package/lib/use-event-listener/use-event-listener.d.ts +1 -1
  161. package/lib/use-hotkeys/parse-hotkey.d.ts +4 -5
  162. package/lib/use-long-press/use-long-press.d.ts +1 -0
  163. package/lib/use-mask/use-mask.d.ts +60 -0
  164. package/lib/use-roving-index/use-roving-index.d.ts +49 -0
  165. package/lib/use-scroll-into-view/use-scroll-into-view.d.ts +4 -1
  166. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"use-long-press.cjs","names":[],"sources":["../../src/use-long-press/use-long-press.ts"],"sourcesContent":["import React, { useEffect, useMemo, useRef } from 'react';\n\nexport interface UseLongPressOptions {\n /** Time in milliseconds to trigger the long press, default is 400ms */\n threshold?: 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 onTouchStart: (event: React.TouchEvent) => void;\n onTouchEnd: (event: React.TouchEvent) => void;\n}\n\nexport function useLongPress(\n onLongPress: (event: React.MouseEvent | React.TouchEvent) => void,\n options: UseLongPressOptions = {}\n): UseLongPressReturnValue {\n const { threshold = 400, onStart, onFinish, onCancel } = options;\n const isLongPressActive = useRef(false);\n const isPressed = useRef(false);\n const timeout = useRef<number>(-1);\n\n useEffect(() => () => window.clearTimeout(timeout.current), []);\n\n return useMemo(() => {\n if (typeof onLongPress !== 'function') {\n return {} as UseLongPressReturnValue;\n }\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 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\n if (timeout.current) {\n window.clearTimeout(timeout.current);\n }\n };\n\n return {\n onMouseDown: start,\n onMouseUp: cancel,\n onMouseLeave: cancel,\n onTouchStart: start,\n onTouchEnd: cancel,\n };\n }, [onLongPress, threshold, onCancel, onFinish, onStart]);\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":";;;AAwBA,SAAgB,aACd,aACA,UAA+B,EAAE,EACR;CACzB,MAAM,EAAE,YAAY,KAAK,SAAS,UAAU,aAAa;CACzD,MAAM,qBAAA,GAAA,MAAA,QAA2B,MAAM;CACvC,MAAM,aAAA,GAAA,MAAA,QAAmB,MAAM;CAC/B,MAAM,WAAA,GAAA,MAAA,QAAyB,GAAG;AAElC,EAAA,GAAA,MAAA,uBAAsB,OAAO,aAAa,QAAQ,QAAQ,EAAE,EAAE,CAAC;AAE/D,SAAA,GAAA,MAAA,eAAqB;AACnB,MAAI,OAAO,gBAAgB,WACzB,QAAO,EAAE;EAGX,MAAM,SAAS,UAA+C;AAC5D,OAAI,CAAC,aAAa,MAAM,IAAI,CAAC,aAAa,MAAM,CAC9C;AAGF,OAAI,QACF,SAAQ,MAAM;AAGhB,aAAU,UAAU;AACpB,WAAQ,UAAU,OAAO,iBAAiB;AACxC,gBAAY,MAAM;AAClB,sBAAkB,UAAU;MAC3B,UAAU;;EAGf,MAAM,UAAU,UAA+C;AAC7D,OAAI,CAAC,aAAa,MAAM,IAAI,CAAC,aAAa,MAAM,CAC9C;AAGF,OAAI,kBAAkB;QAChB,SACF,UAAS,MAAM;cAER,UAAU;QACf,SACF,UAAS,MAAM;;AAInB,qBAAkB,UAAU;AAC5B,aAAU,UAAU;AAEpB,OAAI,QAAQ,QACV,QAAO,aAAa,QAAQ,QAAQ;;AAIxC,SAAO;GACL,aAAa;GACb,WAAW;GACX,cAAc;GACd,cAAc;GACd,YAAY;GACb;IACA;EAAC;EAAa;EAAW;EAAU;EAAU;EAAQ,CAAC;;AAG3D,SAAS,aAAa,OAAuE;AAC3F,QAAO,OAAO,aACV,MAAM,uBAAuB,aAC7B,aAAa,MAAM;;AAGzB,SAAS,aAAa,OAAuE;AAC3F,QAAO,MAAM,uBAAuB"}
1
+ {"version":3,"file":"use-long-press.cjs","names":[],"sources":["../../src/use-long-press/use-long-press.ts"],"sourcesContent":["import React, { useEffect, useMemo, useRef } from 'react';\n\nexport interface UseLongPressOptions {\n /** Time in milliseconds to trigger the long press, default is 400ms */\n threshold?: 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 onTouchStart: (event: React.TouchEvent) => void;\n onTouchEnd: (event: React.TouchEvent) => void;\n onTouchCancel: (event: React.TouchEvent) => void;\n}\n\nexport function useLongPress(\n onLongPress: (event: React.MouseEvent | React.TouchEvent) => void,\n options: UseLongPressOptions = {}\n): UseLongPressReturnValue {\n const { threshold = 400, onStart, onFinish, onCancel } = options;\n const isLongPressActive = useRef(false);\n const isPressed = useRef(false);\n const timeout = useRef<number>(-1);\n\n useEffect(() => () => window.clearTimeout(timeout.current), []);\n\n return useMemo(() => {\n if (typeof onLongPress !== 'function') {\n return {} as UseLongPressReturnValue;\n }\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 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\n if (timeout.current !== -1) {\n window.clearTimeout(timeout.current);\n timeout.current = -1;\n }\n };\n\n return {\n onMouseDown: start,\n onMouseUp: cancel,\n onMouseLeave: cancel,\n onTouchStart: start,\n onTouchEnd: cancel,\n onTouchCancel: cancel,\n };\n }, [onLongPress, threshold, onCancel, onFinish, onStart]);\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":";;;AAyBA,SAAgB,aACd,aACA,UAA+B,EAAE,EACR;CACzB,MAAM,EAAE,YAAY,KAAK,SAAS,UAAU,aAAa;CACzD,MAAM,qBAAA,GAAA,MAAA,QAA2B,MAAM;CACvC,MAAM,aAAA,GAAA,MAAA,QAAmB,MAAM;CAC/B,MAAM,WAAA,GAAA,MAAA,QAAyB,GAAG;AAElC,EAAA,GAAA,MAAA,uBAAsB,OAAO,aAAa,QAAQ,QAAQ,EAAE,EAAE,CAAC;AAE/D,SAAA,GAAA,MAAA,eAAqB;AACnB,MAAI,OAAO,gBAAgB,WACzB,QAAO,EAAE;EAGX,MAAM,SAAS,UAA+C;AAC5D,OAAI,CAAC,aAAa,MAAM,IAAI,CAAC,aAAa,MAAM,CAC9C;AAGF,OAAI,QACF,SAAQ,MAAM;AAGhB,aAAU,UAAU;AACpB,WAAQ,UAAU,OAAO,iBAAiB;AACxC,gBAAY,MAAM;AAClB,sBAAkB,UAAU;MAC3B,UAAU;;EAGf,MAAM,UAAU,UAA+C;AAC7D,OAAI,CAAC,aAAa,MAAM,IAAI,CAAC,aAAa,MAAM,CAC9C;AAGF,OAAI,kBAAkB;QAChB,SACF,UAAS,MAAM;cAER,UAAU;QACf,SACF,UAAS,MAAM;;AAInB,qBAAkB,UAAU;AAC5B,aAAU,UAAU;AAEpB,OAAI,QAAQ,YAAY,IAAI;AAC1B,WAAO,aAAa,QAAQ,QAAQ;AACpC,YAAQ,UAAU;;;AAItB,SAAO;GACL,aAAa;GACb,WAAW;GACX,cAAc;GACd,cAAc;GACd,YAAY;GACZ,eAAe;GAChB;IACA;EAAC;EAAa;EAAW;EAAU;EAAU;EAAQ,CAAC;;AAG3D,SAAS,aAAa,OAAuE;AAC3F,QAAO,OAAO,aACV,MAAM,uBAAuB,aAC7B,aAAa,MAAM;;AAGzB,SAAS,aAAa,OAAuE;AAC3F,QAAO,MAAM,uBAAuB"}
@@ -0,0 +1,457 @@
1
+ "use client";
2
+ let react = require("react");
3
+ //#region packages/@mantine/hooks/src/use-mask/use-mask.ts
4
+ const DEFAULT_TOKENS = {
5
+ "9": /[0-9]/,
6
+ a: /[A-Za-z]/,
7
+ A: /[A-Z]/,
8
+ "*": /[A-Za-z0-9]/,
9
+ "#": /[-+0-9]/
10
+ };
11
+ function parseMask(mask, tokens) {
12
+ if (Array.isArray(mask)) return mask.map((item) => {
13
+ if (item instanceof RegExp) return {
14
+ type: "token",
15
+ char: "_",
16
+ pattern: item
17
+ };
18
+ return {
19
+ type: "literal",
20
+ char: item
21
+ };
22
+ });
23
+ const slots = [];
24
+ let optional = false;
25
+ for (let i = 0; i < mask.length; i++) {
26
+ const char = mask[i];
27
+ if (char === "\\" && i + 1 < mask.length) {
28
+ i++;
29
+ slots.push({
30
+ type: "literal",
31
+ char: mask[i]
32
+ });
33
+ continue;
34
+ }
35
+ if (char === "?") {
36
+ optional = true;
37
+ continue;
38
+ }
39
+ if (tokens[char]) slots.push({
40
+ type: "token",
41
+ char,
42
+ pattern: tokens[char],
43
+ optional
44
+ });
45
+ else slots.push({
46
+ type: "literal",
47
+ char,
48
+ optional
49
+ });
50
+ }
51
+ return slots;
52
+ }
53
+ function getSlotChar(slotCharOption, index) {
54
+ if (slotCharOption === null || slotCharOption === "" || slotCharOption === void 0) return "";
55
+ if (slotCharOption.length > 1) return slotCharOption[index] || "_";
56
+ return slotCharOption;
57
+ }
58
+ function applyMaskToRaw(raw, slots, _slotCharOption, transform) {
59
+ let result = "";
60
+ let rawIndex = 0;
61
+ let slotIndex = 0;
62
+ for (slotIndex = 0; slotIndex < slots.length; slotIndex++) {
63
+ const slot = slots[slotIndex];
64
+ if (slot.type === "literal") result += slot.char;
65
+ else if (rawIndex < raw.length) {
66
+ const ch = transform ? transform(raw[rawIndex]) : raw[rawIndex];
67
+ if (slot.pattern && slot.pattern.test(ch)) {
68
+ result += ch;
69
+ rawIndex++;
70
+ } else {
71
+ rawIndex++;
72
+ slotIndex--;
73
+ }
74
+ } else break;
75
+ }
76
+ return result;
77
+ }
78
+ function buildDisplayValue(value, slots, slotCharOption, showSlots) {
79
+ if (!showSlots) return value;
80
+ let display = value;
81
+ for (let i = value.length; i < slots.length; i++) {
82
+ const slot = slots[i];
83
+ if (slot.type === "literal") display += slot.char;
84
+ else {
85
+ const sc = getSlotChar(slotCharOption, i);
86
+ if (!sc) break;
87
+ display += sc;
88
+ }
89
+ }
90
+ return display;
91
+ }
92
+ function extractRaw(masked, slots) {
93
+ let raw = "";
94
+ for (let i = 0; i < masked.length && i < slots.length; i++) if (slots[i].type === "token") raw += masked[i];
95
+ return raw;
96
+ }
97
+ function checkComplete(masked, slots) {
98
+ for (let i = 0; i < slots.length; i++) if (slots[i].type === "token" && !slots[i].optional) {
99
+ if (i >= masked.length) return false;
100
+ if (!slots[i].pattern.test(masked[i])) return false;
101
+ }
102
+ return true;
103
+ }
104
+ function findNextTokenIndex(slots, from) {
105
+ for (let i = from; i < slots.length; i++) if (slots[i].type === "token") return i;
106
+ return slots.length;
107
+ }
108
+ function findPrevTokenIndex(slots, from) {
109
+ for (let i = from; i >= 0; i--) if (slots[i].type === "token") return i;
110
+ return -1;
111
+ }
112
+ function processInput(inputValue, slots, _slotCharOption) {
113
+ let result = "";
114
+ let inputIndex = 0;
115
+ for (let slotIndex = 0; slotIndex < slots.length && inputIndex <= inputValue.length; slotIndex++) {
116
+ const slot = slots[slotIndex];
117
+ if (slot.type === "literal") {
118
+ result += slot.char;
119
+ if (inputIndex < inputValue.length && inputValue[inputIndex] === slot.char) inputIndex++;
120
+ continue;
121
+ }
122
+ if (inputIndex >= inputValue.length) break;
123
+ while (inputIndex < inputValue.length) {
124
+ const ch = inputValue[inputIndex];
125
+ inputIndex++;
126
+ if (slot.pattern.test(ch)) {
127
+ result += ch;
128
+ break;
129
+ }
130
+ }
131
+ if (result.length <= slotIndex) break;
132
+ }
133
+ return result;
134
+ }
135
+ function getResolvedOptions(options, rawValue) {
136
+ const tokens = {
137
+ ...DEFAULT_TOKENS,
138
+ ...options.tokens
139
+ };
140
+ let mask = options.mask;
141
+ let slotChar = options.slotChar === void 0 ? "_" : options.slotChar;
142
+ let separate = options.separate ?? false;
143
+ if (options.modify) {
144
+ const overrides = options.modify(rawValue);
145
+ if (overrides) {
146
+ if (overrides.mask !== void 0) mask = overrides.mask;
147
+ if (overrides.tokens !== void 0) Object.assign(tokens, overrides.tokens);
148
+ if (overrides.slotChar !== void 0) slotChar = overrides.slotChar;
149
+ if (overrides.separate !== void 0) separate = overrides.separate;
150
+ }
151
+ }
152
+ return {
153
+ slots: parseMask(mask, tokens),
154
+ slotChar,
155
+ separate,
156
+ tokens,
157
+ transform: options.transform
158
+ };
159
+ }
160
+ function formatMask(raw, options) {
161
+ const { slots, slotChar, transform } = getResolvedOptions(options, raw);
162
+ return applyMaskToRaw(raw, slots, slotChar, transform);
163
+ }
164
+ function unformatMask(masked, options) {
165
+ const { slots } = getResolvedOptions(options, "");
166
+ return extractRaw(masked, slots);
167
+ }
168
+ function isMaskComplete(masked, options) {
169
+ const { slots } = getResolvedOptions(options, "");
170
+ return checkComplete(masked, slots);
171
+ }
172
+ function generatePattern(mode, options) {
173
+ const { slots } = getResolvedOptions(options, "");
174
+ let pattern = "";
175
+ for (const slot of slots) if (slot.type === "literal") pattern += slot.char.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
176
+ else {
177
+ const src = slot.pattern.source;
178
+ if (mode === "full-inexact") pattern += slot.optional ? `${src}?` : src;
179
+ else pattern += slot.optional ? `(${src})?` : `(${src})`;
180
+ }
181
+ return pattern;
182
+ }
183
+ function useMask(options) {
184
+ const optionsRef = (0, react.useRef)(options);
185
+ optionsRef.current = options;
186
+ const inputRef = (0, react.useRef)(null);
187
+ const [maskedValue, setMaskedValue] = (0, react.useState)("");
188
+ const [rawValue, setRawValue] = (0, react.useState)("");
189
+ const processedRef = (0, react.useRef)("");
190
+ const wasCompleteRef = (0, react.useRef)(false);
191
+ const isFocusedRef = (0, react.useRef)(false);
192
+ const getOptions = (0, react.useCallback)(() => {
193
+ const opts = optionsRef.current;
194
+ return getResolvedOptions(opts, rawValue);
195
+ }, [rawValue]);
196
+ const updateValue = (0, react.useCallback)((newMasked, cursorPos) => {
197
+ const opts = optionsRef.current;
198
+ const { slots } = getResolvedOptions(opts, extractRaw(newMasked, getResolvedOptions(opts, "").slots));
199
+ const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, extractRaw(newMasked, slots));
200
+ const reprocessed = processInput(newMasked, resolvedSlots, slotChar);
201
+ const newRaw = extractRaw(reprocessed, resolvedSlots);
202
+ const showSlots = opts.alwaysShowMask || isFocusedRef.current;
203
+ const showOnFocus = opts.showMaskOnFocus !== false;
204
+ const displayValue = buildDisplayValue(reprocessed, resolvedSlots, slotChar, showSlots && (showOnFocus || reprocessed.length > 0));
205
+ processedRef.current = reprocessed;
206
+ setMaskedValue(displayValue);
207
+ setRawValue(newRaw);
208
+ if (inputRef.current) {
209
+ inputRef.current.value = displayValue;
210
+ if (cursorPos !== void 0 && document.activeElement === inputRef.current) {
211
+ const pos = Math.min(cursorPos, reprocessed.length);
212
+ inputRef.current.setSelectionRange(pos, pos);
213
+ }
214
+ }
215
+ if (opts.onChangeRaw) opts.onChangeRaw(newRaw, displayValue);
216
+ const complete = checkComplete(reprocessed, resolvedSlots);
217
+ if (complete && !wasCompleteRef.current && opts.onComplete) opts.onComplete(displayValue, newRaw);
218
+ wasCompleteRef.current = complete;
219
+ return {
220
+ displayValue,
221
+ newRaw,
222
+ reprocessed,
223
+ resolvedSlots
224
+ };
225
+ }, [getOptions]);
226
+ const handleInput = (0, react.useCallback)((e) => {
227
+ const input = e.target;
228
+ const opts = optionsRef.current;
229
+ const { slots: resolvedSlots, slotChar, transform } = getResolvedOptions(opts, "");
230
+ const reformatted = applyMaskToRaw(extractRaw(input.value, resolvedSlots), resolvedSlots, slotChar, transform);
231
+ updateValue(reformatted, reformatted.length);
232
+ }, [updateValue]);
233
+ const clampCursorToProcessed = (0, react.useCallback)((input) => {
234
+ const opts = optionsRef.current;
235
+ const { slots } = getResolvedOptions(opts, "");
236
+ const processed = processedRef.current;
237
+ const cursorPos = input.selectionStart ?? 0;
238
+ const maxPos = processed.length > 0 ? findNextEditablePosition(processed.length, slots, processed) : findNextTokenIndex(slots, 0);
239
+ if (cursorPos > maxPos) input.setSelectionRange(maxPos, maxPos);
240
+ }, []);
241
+ const handleFocus = (0, react.useCallback)(() => {
242
+ isFocusedRef.current = true;
243
+ const opts = optionsRef.current;
244
+ const input = inputRef.current;
245
+ if (!input) return;
246
+ const { slots, slotChar } = getResolvedOptions(opts, "");
247
+ const showOnFocus = opts.showMaskOnFocus !== false;
248
+ const processed = processedRef.current;
249
+ if (showOnFocus || opts.alwaysShowMask) {
250
+ const display = buildDisplayValue(processed, slots, slotChar, true);
251
+ input.value = display;
252
+ setMaskedValue(display);
253
+ }
254
+ requestAnimationFrame(() => {
255
+ if (input === document.activeElement) clampCursorToProcessed(input);
256
+ });
257
+ }, [clampCursorToProcessed]);
258
+ const handleMouseUp = (0, react.useCallback)(() => {
259
+ const input = inputRef.current;
260
+ if (!input || input !== document.activeElement) return;
261
+ clampCursorToProcessed(input);
262
+ }, [clampCursorToProcessed]);
263
+ const handleBlur = (0, react.useCallback)(() => {
264
+ isFocusedRef.current = false;
265
+ const opts = optionsRef.current;
266
+ const input = inputRef.current;
267
+ if (!input) return;
268
+ const { slots, slotChar } = getResolvedOptions(opts, rawValue);
269
+ const processed = processInput(input.value, slots, slotChar);
270
+ const complete = checkComplete(processed, slots);
271
+ if (opts.autoClear && !complete && processed.length > 0) {
272
+ input.value = "";
273
+ processedRef.current = "";
274
+ setMaskedValue("");
275
+ setRawValue("");
276
+ wasCompleteRef.current = false;
277
+ if (opts.onChangeRaw) opts.onChangeRaw("", "");
278
+ if (opts.alwaysShowMask) {
279
+ const emptyDisplay = buildDisplayValue("", slots, slotChar, true);
280
+ input.value = emptyDisplay;
281
+ setMaskedValue(emptyDisplay);
282
+ }
283
+ return;
284
+ }
285
+ if (!opts.alwaysShowMask && !complete) {
286
+ const display = buildDisplayValue(processed, slots, slotChar, false);
287
+ input.value = display;
288
+ setMaskedValue(display);
289
+ }
290
+ }, [rawValue]);
291
+ const handleKeyDown = (0, react.useCallback)((e) => {
292
+ const input = e.target;
293
+ const opts = optionsRef.current;
294
+ const { slots, slotChar, transform } = getResolvedOptions(opts, rawValue);
295
+ const start = input.selectionStart ?? 0;
296
+ const end = input.selectionEnd ?? 0;
297
+ const processed = processedRef.current;
298
+ if (e.key === "Backspace") {
299
+ e.preventDefault();
300
+ if (e.metaKey || e.ctrlKey && !e.altKey) {
301
+ const clampedStart = Math.min(start, processed.length);
302
+ updateValue(applyMaskToRaw(extractRaw(processed.slice(clampedStart), slots.slice(clampedStart)), slots, slotChar, transform), 0);
303
+ return;
304
+ }
305
+ if (start !== end) {
306
+ const clampedEnd = Math.min(end, processed.length);
307
+ const before = processed.slice(0, start);
308
+ const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));
309
+ updateValue(applyMaskToRaw(extractRaw(before, slots) + afterRaw, slots, slotChar, transform), start);
310
+ return;
311
+ }
312
+ if (start === 0) return;
313
+ let deletePos = start - 1;
314
+ while (deletePos >= 0 && slots[deletePos] && slots[deletePos].type === "literal") deletePos--;
315
+ if (deletePos < 0) return;
316
+ updateValue(applyMaskToRaw(extractRaw(processed.slice(0, deletePos), slots.slice(0, deletePos)) + extractRaw(processed.slice(deletePos + 1), slots.slice(deletePos + 1)), slots, slotChar, transform), deletePos);
317
+ } else if (e.key === "Delete") {
318
+ e.preventDefault();
319
+ if (start !== end) {
320
+ const clampedEnd = Math.min(end, processed.length);
321
+ const before = processed.slice(0, start);
322
+ const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));
323
+ updateValue(applyMaskToRaw(extractRaw(before, slots) + afterRaw, slots, slotChar, transform), start);
324
+ return;
325
+ }
326
+ let deletePos = start;
327
+ while (deletePos < slots.length && slots[deletePos] && slots[deletePos].type === "literal") deletePos++;
328
+ if (deletePos >= processed.length) return;
329
+ updateValue(applyMaskToRaw(extractRaw(processed.slice(0, start), slots.slice(0, start)) + extractRaw(processed.slice(deletePos + 1), slots.slice(deletePos + 1)), slots, slotChar, transform), start);
330
+ } else if (e.key === "ArrowRight" && !e.shiftKey) {
331
+ const nextPos = findNextEditablePosition(start + 1, slots, input.value);
332
+ if (nextPos !== start + 1) {
333
+ e.preventDefault();
334
+ input.setSelectionRange(nextPos, nextPos);
335
+ }
336
+ } else if (e.key === "ArrowLeft" && !e.shiftKey) {
337
+ if (start > 0) {
338
+ const prevToken = findPrevTokenIndex(slots, start - 1);
339
+ if (prevToken >= 0 && prevToken !== start - 1) {
340
+ e.preventDefault();
341
+ input.setSelectionRange(prevToken + 1, prevToken + 1);
342
+ }
343
+ }
344
+ } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
345
+ e.preventDefault();
346
+ let insertPos = Math.min(start, processed.length);
347
+ while (insertPos < slots.length && slots[insertPos] && slots[insertPos].type === "literal") insertPos++;
348
+ if (insertPos >= slots.length) return;
349
+ const slot = slots[insertPos];
350
+ const ch = transform ? transform(e.key) : e.key;
351
+ if (!slot.pattern.test(ch)) return;
352
+ const beforeRaw = extractRaw(processed.slice(0, insertPos), slots.slice(0, insertPos));
353
+ const afterRaw = start < end ? extractRaw(processed.slice(Math.min(end, processed.length)), slots.slice(Math.min(end, processed.length))) : extractRaw(processed.slice(insertPos), slots.slice(insertPos));
354
+ const newValue = applyMaskToRaw(beforeRaw + ch + afterRaw, slots, slotChar, transform);
355
+ updateValue(newValue, findNextEditablePosition(insertPos + 1, slots, newValue));
356
+ }
357
+ }, [rawValue, updateValue]);
358
+ const handlePaste = (0, react.useCallback)((e) => {
359
+ e.preventDefault();
360
+ const input = e.target;
361
+ const opts = optionsRef.current;
362
+ const pastedText = e.clipboardData?.getData("text") ?? "";
363
+ const start = input.selectionStart ?? 0;
364
+ const end = input.selectionEnd ?? 0;
365
+ const processed = processedRef.current;
366
+ const { slots, slotChar, transform } = getResolvedOptions(opts, "");
367
+ const clampedEnd = Math.min(end, processed.length);
368
+ const beforeRaw = extractRaw(processed.slice(0, start), slots.slice(0, start));
369
+ const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));
370
+ const newValue = applyMaskToRaw(beforeRaw + pastedText + afterRaw, slots, slotChar, transform);
371
+ const { reprocessed } = updateValue(newValue);
372
+ const pasteEndPos = Math.min((reprocessed || newValue).length, slots.length);
373
+ if (input === document.activeElement) input.setSelectionRange(pasteEndPos, pasteEndPos);
374
+ }, [updateValue]);
375
+ const setAriaAttributes = (0, react.useCallback)((input) => {
376
+ if (optionsRef.current.invalid) input.setAttribute("aria-invalid", "true");
377
+ else input.removeAttribute("aria-invalid");
378
+ }, []);
379
+ const refCallback = (0, react.useCallback)((node) => {
380
+ const prevInput = inputRef.current;
381
+ if (prevInput) {
382
+ prevInput.removeEventListener("input", handleInput);
383
+ prevInput.removeEventListener("focus", handleFocus);
384
+ prevInput.removeEventListener("blur", handleBlur);
385
+ prevInput.removeEventListener("mouseup", handleMouseUp);
386
+ prevInput.removeEventListener("keydown", handleKeyDown);
387
+ prevInput.removeEventListener("paste", handlePaste);
388
+ }
389
+ inputRef.current = node;
390
+ if (node) {
391
+ node.addEventListener("input", handleInput);
392
+ node.addEventListener("focus", handleFocus);
393
+ node.addEventListener("blur", handleBlur);
394
+ node.addEventListener("mouseup", handleMouseUp);
395
+ node.addEventListener("keydown", handleKeyDown);
396
+ node.addEventListener("paste", handlePaste);
397
+ setAriaAttributes(node);
398
+ if (options.alwaysShowMask && !node.value) {
399
+ const { slots, slotChar } = getResolvedOptions(options, "");
400
+ const display = buildDisplayValue("", slots, slotChar, true);
401
+ node.value = display;
402
+ setMaskedValue(display);
403
+ }
404
+ }
405
+ }, [
406
+ handleInput,
407
+ handleFocus,
408
+ handleBlur,
409
+ handleMouseUp,
410
+ handleKeyDown,
411
+ handlePaste,
412
+ setAriaAttributes,
413
+ options
414
+ ]);
415
+ (0, react.useEffect)(() => {
416
+ const input = inputRef.current;
417
+ if (!input) return;
418
+ setAriaAttributes(input);
419
+ }, [options.invalid, setAriaAttributes]);
420
+ return {
421
+ ref: refCallback,
422
+ value: maskedValue,
423
+ rawValue,
424
+ isComplete: (() => {
425
+ const { slots } = getOptions();
426
+ return checkComplete(processedRef.current, slots);
427
+ })(),
428
+ reset: (0, react.useCallback)(() => {
429
+ const opts = optionsRef.current;
430
+ const input = inputRef.current;
431
+ processedRef.current = "";
432
+ setMaskedValue("");
433
+ setRawValue("");
434
+ wasCompleteRef.current = false;
435
+ if (input) if (opts.alwaysShowMask) {
436
+ const { slots, slotChar } = getResolvedOptions(opts, "");
437
+ const display = buildDisplayValue("", slots, slotChar, true);
438
+ input.value = display;
439
+ setMaskedValue(display);
440
+ } else input.value = "";
441
+ if (opts.onChangeRaw) opts.onChangeRaw("", "");
442
+ }, [])
443
+ };
444
+ }
445
+ function findNextEditablePosition(from, slots, value) {
446
+ let pos = from;
447
+ while (pos < slots.length && pos < value.length && slots[pos] && slots[pos].type === "literal") pos++;
448
+ return pos;
449
+ }
450
+ //#endregion
451
+ exports.formatMask = formatMask;
452
+ exports.generatePattern = generatePattern;
453
+ exports.isMaskComplete = isMaskComplete;
454
+ exports.unformatMask = unformatMask;
455
+ exports.useMask = useMask;
456
+
457
+ //# sourceMappingURL=use-mask.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mask.cjs","names":[],"sources":["../../src/use-mask/use-mask.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nconst DEFAULT_TOKENS: Record<string, RegExp> = {\n '9': /[0-9]/,\n a: /[A-Za-z]/,\n A: /[A-Z]/,\n '*': /[A-Za-z0-9]/,\n '#': /[-+0-9]/,\n};\n\nexport interface UseMaskOptions {\n /** Mask pattern string or array of string literals and RegExp objects */\n mask: string | Array<string | RegExp>;\n\n /** Override or extend the default token map */\n tokens?: Record<string, RegExp>;\n\n /** Called before masking on each keystroke, can return overrides for mask options */\n modify?: (\n value: string\n ) => Partial<Pick<UseMaskOptions, 'mask' | 'tokens' | 'slotChar' | 'separate'>> | undefined;\n\n /** When true, raw and display values are decoupled */\n separate?: boolean;\n\n /** Character displayed in unfilled slots, `\"_\"` by default */\n slotChar?: string | null;\n\n /** Show mask pattern even when field is empty and unfocused */\n alwaysShowMask?: boolean;\n\n /** Show mask placeholder on focus, `true` by default */\n showMaskOnFocus?: boolean;\n\n /** Transform each character before validation and insertion */\n transform?: (char: string) => string;\n\n /** Clear value on blur when mask is incomplete, `false` by default */\n autoClear?: boolean;\n\n /** Sets aria-invalid on the input */\n invalid?: boolean;\n\n /** Called on every change with raw and masked values */\n onChangeRaw?: (rawValue: string, maskedValue: string) => void;\n\n /** Called when all required mask slots are filled */\n onComplete?: (maskedValue: string, rawValue: string) => void;\n\n /** Escape hatch for advanced cursor/value manipulation */\n beforeMaskedStateChange?: (states: {\n previousState: MaskState;\n currentState: MaskState;\n nextState: MaskState;\n }) => MaskState;\n}\n\nexport interface MaskState {\n value: string;\n selection: { start: number; end: number } | null;\n}\n\nexport interface UseMaskReturnValue {\n /** Ref to attach to the input element */\n ref: React.RefCallback<HTMLInputElement>;\n\n /** Current masked display value */\n value: string;\n\n /** Current raw unmasked value */\n rawValue: string;\n\n /** Whether all required mask slots are filled */\n isComplete: boolean;\n\n /** Clear the input value and reset state */\n reset: () => void;\n}\n\ninterface MaskSlot {\n type: 'token' | 'literal';\n char: string;\n pattern?: RegExp;\n optional?: boolean;\n}\n\nfunction parseMask(\n mask: string | Array<string | RegExp>,\n tokens: Record<string, RegExp>\n): MaskSlot[] {\n if (Array.isArray(mask)) {\n return mask.map((item) => {\n if (item instanceof RegExp) {\n return { type: 'token', char: '_', pattern: item };\n }\n return { type: 'literal', char: item };\n });\n }\n\n const slots: MaskSlot[] = [];\n let optional = false;\n\n for (let i = 0; i < mask.length; i++) {\n const char = mask[i];\n\n if (char === '\\\\' && i + 1 < mask.length) {\n i++;\n slots.push({ type: 'literal', char: mask[i] });\n continue;\n }\n\n if (char === '?') {\n optional = true;\n continue;\n }\n\n if (tokens[char]) {\n slots.push({ type: 'token', char, pattern: tokens[char], optional });\n } else {\n slots.push({ type: 'literal', char, optional });\n }\n }\n\n return slots;\n}\n\nfunction getSlotChar(slotCharOption: string | null | undefined, index: number): string {\n if (slotCharOption === null || slotCharOption === '' || slotCharOption === undefined) {\n return '';\n }\n if (slotCharOption.length > 1) {\n return slotCharOption[index] || '_';\n }\n return slotCharOption;\n}\n\nfunction applyMaskToRaw(\n raw: string,\n slots: MaskSlot[],\n _slotCharOption: string | null | undefined,\n transform?: (char: string) => string\n): string {\n let result = '';\n let rawIndex = 0;\n let slotIndex = 0;\n\n for (slotIndex = 0; slotIndex < slots.length; slotIndex++) {\n const slot = slots[slotIndex];\n if (slot.type === 'literal') {\n result += slot.char;\n } else if (rawIndex < raw.length) {\n const ch = transform ? transform(raw[rawIndex]) : raw[rawIndex];\n if (slot.pattern && slot.pattern.test(ch)) {\n result += ch;\n rawIndex++;\n } else {\n rawIndex++;\n slotIndex--;\n }\n } else {\n break;\n }\n }\n\n return result;\n}\n\nfunction buildDisplayValue(\n value: string,\n slots: MaskSlot[],\n slotCharOption: string | null | undefined,\n showSlots: boolean\n): string {\n if (!showSlots) {\n return value;\n }\n\n let display = value;\n\n for (let i = value.length; i < slots.length; i++) {\n const slot = slots[i];\n if (slot.type === 'literal') {\n display += slot.char;\n } else {\n const sc = getSlotChar(slotCharOption, i);\n if (!sc) {\n break;\n }\n display += sc;\n }\n }\n\n return display;\n}\n\nfunction extractRaw(masked: string, slots: MaskSlot[]): string {\n let raw = '';\n for (let i = 0; i < masked.length && i < slots.length; i++) {\n if (slots[i].type === 'token') {\n raw += masked[i];\n }\n }\n return raw;\n}\n\nfunction checkComplete(masked: string, slots: MaskSlot[]): boolean {\n for (let i = 0; i < slots.length; i++) {\n if (slots[i].type === 'token' && !slots[i].optional) {\n if (i >= masked.length) {\n return false;\n }\n if (!slots[i].pattern!.test(masked[i])) {\n return false;\n }\n }\n }\n return true;\n}\n\nfunction findNextTokenIndex(slots: MaskSlot[], from: number): number {\n for (let i = from; i < slots.length; i++) {\n if (slots[i].type === 'token') {\n return i;\n }\n }\n return slots.length;\n}\n\nfunction findPrevTokenIndex(slots: MaskSlot[], from: number): number {\n for (let i = from; i >= 0; i--) {\n if (slots[i].type === 'token') {\n return i;\n }\n }\n return -1;\n}\n\nfunction processInput(\n inputValue: string,\n slots: MaskSlot[],\n _slotCharOption: string | null | undefined\n): string {\n let result = '';\n let inputIndex = 0;\n\n for (\n let slotIndex = 0;\n slotIndex < slots.length && inputIndex <= inputValue.length;\n slotIndex++\n ) {\n const slot = slots[slotIndex];\n\n if (slot.type === 'literal') {\n result += slot.char;\n if (inputIndex < inputValue.length && inputValue[inputIndex] === slot.char) {\n inputIndex++;\n }\n continue;\n }\n\n if (inputIndex >= inputValue.length) {\n break;\n }\n\n while (inputIndex < inputValue.length) {\n const ch = inputValue[inputIndex];\n inputIndex++;\n\n if (slot.pattern!.test(ch)) {\n result += ch;\n break;\n }\n }\n\n if (result.length <= slotIndex) {\n break;\n }\n }\n\n return result;\n}\n\nfunction getResolvedOptions(options: UseMaskOptions, rawValue: string) {\n const tokens = { ...DEFAULT_TOKENS, ...options.tokens };\n let mask = options.mask;\n let slotChar: string | null | undefined = options.slotChar === undefined ? '_' : options.slotChar;\n let separate = options.separate ?? false;\n\n if (options.modify) {\n const overrides = options.modify(rawValue);\n if (overrides) {\n if (overrides.mask !== undefined) {\n mask = overrides.mask;\n }\n if (overrides.tokens !== undefined) {\n Object.assign(tokens, overrides.tokens);\n }\n if (overrides.slotChar !== undefined) {\n slotChar = overrides.slotChar;\n }\n if (overrides.separate !== undefined) {\n separate = overrides.separate;\n }\n }\n }\n\n const slots = parseMask(mask, tokens);\n return { slots, slotChar, separate, tokens, transform: options.transform };\n}\n\nexport function formatMask(raw: string, options: UseMaskOptions): string {\n const { slots, slotChar, transform } = getResolvedOptions(options, raw);\n return applyMaskToRaw(raw, slots, slotChar, transform);\n}\n\nexport function unformatMask(masked: string, options: UseMaskOptions): string {\n const { slots } = getResolvedOptions(options, '');\n return extractRaw(masked, slots);\n}\n\nexport function isMaskComplete(masked: string, options: UseMaskOptions): boolean {\n const { slots } = getResolvedOptions(options, '');\n return checkComplete(masked, slots);\n}\n\nexport function generatePattern(mode: 'full' | 'full-inexact', options: UseMaskOptions): string {\n const { slots } = getResolvedOptions(options, '');\n let pattern = '';\n\n for (const slot of slots) {\n if (slot.type === 'literal') {\n pattern += slot.char.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n } else {\n const src = slot.pattern!.source;\n if (mode === 'full-inexact') {\n pattern += slot.optional ? `${src}?` : src;\n } else {\n pattern += slot.optional ? `(${src})?` : `(${src})`;\n }\n }\n }\n\n return pattern;\n}\n\nexport function useMask(options: UseMaskOptions): UseMaskReturnValue {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n const [maskedValue, setMaskedValue] = useState('');\n const [rawValue, setRawValue] = useState('');\n const processedRef = useRef('');\n const wasCompleteRef = useRef(false);\n const isFocusedRef = useRef(false);\n\n const getOptions = useCallback(() => {\n const opts = optionsRef.current;\n return getResolvedOptions(opts, rawValue);\n }, [rawValue]);\n\n const updateValue = useCallback(\n (newMasked: string, cursorPos?: number) => {\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(\n opts,\n extractRaw(newMasked, getResolvedOptions(opts, '').slots)\n );\n const raw = extractRaw(newMasked, slots);\n\n const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, raw);\n\n const reprocessed = processInput(newMasked, resolvedSlots, slotChar);\n const newRaw = extractRaw(reprocessed, resolvedSlots);\n\n const showSlots = opts.alwaysShowMask || isFocusedRef.current;\n const showOnFocus = opts.showMaskOnFocus !== false;\n const shouldShowSlots = showSlots && (showOnFocus || reprocessed.length > 0);\n\n const displayValue = buildDisplayValue(reprocessed, resolvedSlots, slotChar, shouldShowSlots);\n\n processedRef.current = reprocessed;\n setMaskedValue(displayValue);\n setRawValue(newRaw);\n\n if (inputRef.current) {\n inputRef.current.value = displayValue;\n if (cursorPos !== undefined && document.activeElement === inputRef.current) {\n const pos = Math.min(cursorPos, reprocessed.length);\n inputRef.current.setSelectionRange(pos, pos);\n }\n }\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw(newRaw, displayValue);\n }\n\n const complete = checkComplete(reprocessed, resolvedSlots);\n if (complete && !wasCompleteRef.current && opts.onComplete) {\n opts.onComplete(displayValue, newRaw);\n }\n wasCompleteRef.current = complete;\n\n return { displayValue, newRaw, reprocessed, resolvedSlots };\n },\n [getOptions]\n );\n\n const handleInput = useCallback(\n (e: Event) => {\n const input = e.target as HTMLInputElement;\n const opts = optionsRef.current;\n\n const { slots: resolvedSlots, slotChar, transform } = getResolvedOptions(opts, '');\n const raw = extractRaw(input.value, resolvedSlots);\n const reformatted = applyMaskToRaw(raw, resolvedSlots, slotChar, transform);\n updateValue(reformatted, reformatted.length);\n },\n [updateValue]\n );\n\n const clampCursorToProcessed = useCallback((input: HTMLInputElement) => {\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(opts, '');\n const processed = processedRef.current;\n const cursorPos = input.selectionStart ?? 0;\n const maxPos =\n processed.length > 0\n ? findNextEditablePosition(processed.length, slots, processed)\n : findNextTokenIndex(slots, 0);\n\n if (cursorPos > maxPos) {\n input.setSelectionRange(maxPos, maxPos);\n }\n }, []);\n\n const handleFocus = useCallback(() => {\n isFocusedRef.current = true;\n const opts = optionsRef.current;\n const input = inputRef.current;\n\n if (!input) {\n return;\n }\n\n const { slots, slotChar } = getResolvedOptions(opts, '');\n const showOnFocus = opts.showMaskOnFocus !== false;\n const processed = processedRef.current;\n\n if (showOnFocus || opts.alwaysShowMask) {\n const display = buildDisplayValue(processed, slots, slotChar, true);\n input.value = display;\n setMaskedValue(display);\n }\n\n requestAnimationFrame(() => {\n if (input === document.activeElement) {\n clampCursorToProcessed(input);\n }\n });\n }, [clampCursorToProcessed]);\n\n const handleMouseUp = useCallback(() => {\n const input = inputRef.current;\n if (!input || input !== document.activeElement) {\n return;\n }\n\n clampCursorToProcessed(input);\n }, [clampCursorToProcessed]);\n\n const handleBlur = useCallback(() => {\n isFocusedRef.current = false;\n const opts = optionsRef.current;\n const input = inputRef.current;\n\n if (!input) {\n return;\n }\n\n const { slots, slotChar } = getResolvedOptions(opts, rawValue);\n const processed = processInput(input.value, slots, slotChar);\n const complete = checkComplete(processed, slots);\n\n if (opts.autoClear && !complete && processed.length > 0) {\n input.value = '';\n processedRef.current = '';\n setMaskedValue('');\n setRawValue('');\n wasCompleteRef.current = false;\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw('', '');\n }\n\n if (opts.alwaysShowMask) {\n const emptyDisplay = buildDisplayValue('', slots, slotChar, true);\n input.value = emptyDisplay;\n setMaskedValue(emptyDisplay);\n }\n return;\n }\n\n if (!opts.alwaysShowMask && !complete) {\n const display = buildDisplayValue(processed, slots, slotChar, false);\n input.value = display;\n setMaskedValue(display);\n }\n }, [rawValue]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n const input = e.target as HTMLInputElement;\n const opts = optionsRef.current;\n\n const { slots, slotChar, transform } = getResolvedOptions(opts, rawValue);\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const processed = processedRef.current;\n\n if (e.key === 'Backspace') {\n e.preventDefault();\n\n if (e.metaKey || (e.ctrlKey && !e.altKey)) {\n const clampedStart = Math.min(start, processed.length);\n const afterRaw = extractRaw(processed.slice(clampedStart), slots.slice(clampedStart));\n const newValue = applyMaskToRaw(afterRaw, slots, slotChar, transform);\n updateValue(newValue, 0);\n return;\n }\n\n if (start !== end) {\n const clampedEnd = Math.min(end, processed.length);\n const before = processed.slice(0, start);\n const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));\n const newValue = applyMaskToRaw(\n extractRaw(before, slots) + afterRaw,\n slots,\n slotChar,\n transform\n );\n updateValue(newValue, start);\n return;\n }\n\n if (start === 0) {\n return;\n }\n\n let deletePos = start - 1;\n while (deletePos >= 0 && slots[deletePos] && slots[deletePos].type === 'literal') {\n deletePos--;\n }\n\n if (deletePos < 0) {\n return;\n }\n\n const beforeRaw = extractRaw(processed.slice(0, deletePos), slots.slice(0, deletePos));\n const afterRaw = extractRaw(processed.slice(deletePos + 1), slots.slice(deletePos + 1));\n const newValue = applyMaskToRaw(beforeRaw + afterRaw, slots, slotChar, transform);\n updateValue(newValue, deletePos);\n } else if (e.key === 'Delete') {\n e.preventDefault();\n\n if (start !== end) {\n const clampedEnd = Math.min(end, processed.length);\n const before = processed.slice(0, start);\n const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));\n const newValue = applyMaskToRaw(\n extractRaw(before, slots) + afterRaw,\n slots,\n slotChar,\n transform\n );\n updateValue(newValue, start);\n return;\n }\n\n let deletePos = start;\n while (\n deletePos < slots.length &&\n slots[deletePos] &&\n slots[deletePos].type === 'literal'\n ) {\n deletePos++;\n }\n\n if (deletePos >= processed.length) {\n return;\n }\n\n const beforeRaw = extractRaw(processed.slice(0, start), slots.slice(0, start));\n const afterRaw = extractRaw(processed.slice(deletePos + 1), slots.slice(deletePos + 1));\n const newValue = applyMaskToRaw(beforeRaw + afterRaw, slots, slotChar, transform);\n updateValue(newValue, start);\n } else if (e.key === 'ArrowRight' && !e.shiftKey) {\n const nextPos = findNextEditablePosition(start + 1, slots, input.value);\n if (nextPos !== start + 1) {\n e.preventDefault();\n input.setSelectionRange(nextPos, nextPos);\n }\n } else if (e.key === 'ArrowLeft' && !e.shiftKey) {\n if (start > 0) {\n const prevToken = findPrevTokenIndex(slots, start - 1);\n if (prevToken >= 0 && prevToken !== start - 1) {\n e.preventDefault();\n input.setSelectionRange(prevToken + 1, prevToken + 1);\n }\n }\n } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {\n e.preventDefault();\n\n let insertPos = Math.min(start, processed.length);\n while (\n insertPos < slots.length &&\n slots[insertPos] &&\n slots[insertPos].type === 'literal'\n ) {\n insertPos++;\n }\n\n if (insertPos >= slots.length) {\n return;\n }\n\n const slot = slots[insertPos];\n const ch = transform ? transform(e.key) : e.key;\n if (!slot.pattern!.test(ch)) {\n return;\n }\n\n const beforeRaw = extractRaw(processed.slice(0, insertPos), slots.slice(0, insertPos));\n const afterRaw =\n start < end\n ? extractRaw(\n processed.slice(Math.min(end, processed.length)),\n slots.slice(Math.min(end, processed.length))\n )\n : extractRaw(processed.slice(insertPos), slots.slice(insertPos));\n const newValue = applyMaskToRaw(beforeRaw + ch + afterRaw, slots, slotChar, transform);\n const newCursorPos = findNextEditablePosition(insertPos + 1, slots, newValue);\n updateValue(newValue, newCursorPos);\n }\n },\n [rawValue, updateValue]\n );\n\n const handlePaste = useCallback(\n (e: ClipboardEvent) => {\n e.preventDefault();\n const input = e.target as HTMLInputElement;\n const opts = optionsRef.current;\n\n const pastedText = e.clipboardData?.getData('text') ?? '';\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const processed = processedRef.current;\n\n const { slots, slotChar, transform } = getResolvedOptions(opts, '');\n const clampedEnd = Math.min(end, processed.length);\n const beforeRaw = extractRaw(processed.slice(0, start), slots.slice(0, start));\n const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));\n const newValue = applyMaskToRaw(\n beforeRaw + pastedText + afterRaw,\n slots,\n slotChar,\n transform\n );\n\n const { reprocessed } = updateValue(newValue);\n\n const pasteEndPos = Math.min((reprocessed || newValue).length, slots.length);\n if (input === document.activeElement) {\n input.setSelectionRange(pasteEndPos, pasteEndPos);\n }\n },\n [updateValue]\n );\n\n const setAriaAttributes = useCallback((input: HTMLInputElement) => {\n const opts = optionsRef.current;\n\n if (opts.invalid) {\n input.setAttribute('aria-invalid', 'true');\n } else {\n input.removeAttribute('aria-invalid');\n }\n }, []);\n\n const refCallback = useCallback(\n (node: HTMLInputElement | null) => {\n const prevInput = inputRef.current;\n\n if (prevInput) {\n prevInput.removeEventListener('input', handleInput);\n prevInput.removeEventListener('focus', handleFocus);\n prevInput.removeEventListener('blur', handleBlur);\n prevInput.removeEventListener('mouseup', handleMouseUp);\n prevInput.removeEventListener('keydown', handleKeyDown as EventListener);\n prevInput.removeEventListener('paste', handlePaste as EventListener);\n }\n\n inputRef.current = node;\n\n if (node) {\n node.addEventListener('input', handleInput);\n node.addEventListener('focus', handleFocus);\n node.addEventListener('blur', handleBlur);\n node.addEventListener('mouseup', handleMouseUp);\n node.addEventListener('keydown', handleKeyDown as EventListener);\n node.addEventListener('paste', handlePaste as EventListener);\n\n setAriaAttributes(node);\n\n if (options.alwaysShowMask && !node.value) {\n const { slots, slotChar } = getResolvedOptions(options, '');\n const display = buildDisplayValue('', slots, slotChar, true);\n node.value = display;\n setMaskedValue(display);\n }\n }\n },\n [\n handleInput,\n handleFocus,\n handleBlur,\n handleMouseUp,\n handleKeyDown,\n handlePaste,\n setAriaAttributes,\n options,\n ]\n );\n\n useEffect(() => {\n const input = inputRef.current;\n if (!input) {\n return;\n }\n\n setAriaAttributes(input);\n }, [options.invalid, setAriaAttributes]);\n\n const isComplete = (() => {\n const { slots } = getOptions();\n return checkComplete(processedRef.current, slots);\n })();\n\n const reset = useCallback(() => {\n const opts = optionsRef.current;\n const input = inputRef.current;\n\n processedRef.current = '';\n setMaskedValue('');\n setRawValue('');\n wasCompleteRef.current = false;\n\n if (input) {\n if (opts.alwaysShowMask) {\n const { slots, slotChar } = getResolvedOptions(opts, '');\n const display = buildDisplayValue('', slots, slotChar, true);\n input.value = display;\n setMaskedValue(display);\n } else {\n input.value = '';\n }\n }\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw('', '');\n }\n }, []);\n\n return {\n ref: refCallback,\n value: maskedValue,\n rawValue,\n isComplete,\n reset,\n };\n}\n\nfunction findNextEditablePosition(from: number, slots: MaskSlot[], value: string): number {\n let pos = from;\n while (pos < slots.length && pos < value.length && slots[pos] && slots[pos].type === 'literal') {\n pos++;\n }\n return pos;\n}\n\nexport namespace useMask {\n export type Options = UseMaskOptions;\n export type ReturnValue = UseMaskReturnValue;\n}\n"],"mappings":"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"}
@@ -13,8 +13,8 @@ function useMouse(options = { resetOnExit: false }) {
13
13
  if (node) {
14
14
  const rect = node.getBoundingClientRect();
15
15
  setPosition({
16
- x: Math.max(0, Math.round(mouseEvent.pageX - rect.left - (window.scrollX || window.scrollX))),
17
- y: Math.max(0, Math.round(mouseEvent.pageY - rect.top - (window.scrollY || window.scrollY)))
16
+ x: Math.max(0, Math.round(mouseEvent.clientX - rect.left)),
17
+ y: Math.max(0, Math.round(mouseEvent.clientY - rect.top))
18
18
  });
19
19
  } else setPosition({
20
20
  x: mouseEvent.clientX,
@@ -1 +1 @@
1
- {"version":3,"file":"use-mouse.cjs","names":[],"sources":["../../src/use-mouse/use-mouse.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\nexport interface UseMouseReturnValue<T extends HTMLElement = any> {\n ref: React.RefCallback<T | null>;\n x: number;\n y: number;\n}\n\nexport function useMouse<T extends HTMLElement = any>(\n options: { resetOnExit?: boolean } = { resetOnExit: false }\n): UseMouseReturnValue<T> {\n const [position, setPosition] = useState({ x: 0, y: 0 });\n\n const refCallback: React.RefCallback<T | null> = useCallback(\n (node) => {\n const setMousePosition = (event: Event) => {\n const mouseEvent = event as globalThis.MouseEvent;\n if (node) {\n const rect = node.getBoundingClientRect();\n\n const x = Math.max(\n 0,\n Math.round(mouseEvent.pageX - rect.left - (window.scrollX || window.scrollX))\n );\n\n const y = Math.max(\n 0,\n Math.round(mouseEvent.pageY - rect.top - (window.scrollY || window.scrollY))\n );\n\n setPosition({ x, y });\n } else {\n setPosition({ x: mouseEvent.clientX, y: mouseEvent.clientY });\n }\n };\n\n const resetMousePosition = () => setPosition({ x: 0, y: 0 });\n\n node?.addEventListener('mousemove', setMousePosition);\n if (options.resetOnExit) {\n node?.addEventListener('mouseleave', resetMousePosition);\n }\n\n return () => {\n node?.removeEventListener('mousemove', setMousePosition);\n if (options.resetOnExit) {\n node?.removeEventListener('mouseleave', resetMousePosition);\n }\n };\n },\n [options.resetOnExit]\n );\n\n return { ref: refCallback, ...position };\n}\n\nexport interface UseMousePositionReturnValue {\n x: number;\n y: number;\n}\n\nexport function useMousePosition(): UseMousePositionReturnValue {\n const [position, setPosition] = useState({ x: 0, y: 0 });\n\n useEffect(() => {\n const setMousePosition = (event: MouseEvent) => {\n setPosition({ x: event.clientX, y: event.clientY });\n };\n\n document.addEventListener('mousemove', setMousePosition);\n\n return () => {\n document.removeEventListener('mousemove', setMousePosition);\n };\n }, []);\n\n return position;\n}\n\nexport namespace useMouse {\n export type ReturnValue<T extends HTMLElement> = UseMouseReturnValue<T>;\n}\n\nexport namespace useMousePosition {\n export type ReturnValue = UseMousePositionReturnValue;\n}\n"],"mappings":";;;AAQA,SAAgB,SACd,UAAqC,EAAE,aAAa,OAAO,EACnC;CACxB,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,UAAwB;EAAE,GAAG;EAAG,GAAG;EAAG,CAAC;AA0CxD,QAAO;EAAE,MAAA,GAAA,MAAA,cAvCN,SAAS;GACR,MAAM,oBAAoB,UAAiB;IACzC,MAAM,aAAa;AACnB,QAAI,MAAM;KACR,MAAM,OAAO,KAAK,uBAAuB;AAYzC,iBAAY;MAAE,GAVJ,KAAK,IACb,GACA,KAAK,MAAM,WAAW,QAAQ,KAAK,QAAQ,OAAO,WAAW,OAAO,SAAS,CAC9E;MAOgB,GALP,KAAK,IACb,GACA,KAAK,MAAM,WAAW,QAAQ,KAAK,OAAO,OAAO,WAAW,OAAO,SAAS,CAC7E;MAEmB,CAAC;UAErB,aAAY;KAAE,GAAG,WAAW;KAAS,GAAG,WAAW;KAAS,CAAC;;GAIjE,MAAM,2BAA2B,YAAY;IAAE,GAAG;IAAG,GAAG;IAAG,CAAC;AAE5D,SAAM,iBAAiB,aAAa,iBAAiB;AACrD,OAAI,QAAQ,YACV,OAAM,iBAAiB,cAAc,mBAAmB;AAG1D,gBAAa;AACX,UAAM,oBAAoB,aAAa,iBAAiB;AACxD,QAAI,QAAQ,YACV,OAAM,oBAAoB,cAAc,mBAAmB;;KAIjE,CAAC,QAAQ,YAAY,CACtB;EAE0B,GAAG;EAAU;;AAQ1C,SAAgB,mBAAgD;CAC9D,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,UAAwB;EAAE,GAAG;EAAG,GAAG;EAAG,CAAC;AAExD,EAAA,GAAA,MAAA,iBAAgB;EACd,MAAM,oBAAoB,UAAsB;AAC9C,eAAY;IAAE,GAAG,MAAM;IAAS,GAAG,MAAM;IAAS,CAAC;;AAGrD,WAAS,iBAAiB,aAAa,iBAAiB;AAExD,eAAa;AACX,YAAS,oBAAoB,aAAa,iBAAiB;;IAE5D,EAAE,CAAC;AAEN,QAAO"}
1
+ {"version":3,"file":"use-mouse.cjs","names":[],"sources":["../../src/use-mouse/use-mouse.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\nexport interface UseMouseReturnValue<T extends HTMLElement = any> {\n ref: React.RefCallback<T | null>;\n x: number;\n y: number;\n}\n\nexport function useMouse<T extends HTMLElement = any>(\n options: { resetOnExit?: boolean } = { resetOnExit: false }\n): UseMouseReturnValue<T> {\n const [position, setPosition] = useState({ x: 0, y: 0 });\n\n const refCallback: React.RefCallback<T | null> = useCallback(\n (node) => {\n const setMousePosition = (event: Event) => {\n const mouseEvent = event as globalThis.MouseEvent;\n if (node) {\n const rect = node.getBoundingClientRect();\n\n const x = Math.max(0, Math.round(mouseEvent.clientX - rect.left));\n\n const y = Math.max(0, Math.round(mouseEvent.clientY - rect.top));\n\n setPosition({ x, y });\n } else {\n setPosition({ x: mouseEvent.clientX, y: mouseEvent.clientY });\n }\n };\n\n const resetMousePosition = () => setPosition({ x: 0, y: 0 });\n\n node?.addEventListener('mousemove', setMousePosition);\n if (options.resetOnExit) {\n node?.addEventListener('mouseleave', resetMousePosition);\n }\n\n return () => {\n node?.removeEventListener('mousemove', setMousePosition);\n if (options.resetOnExit) {\n node?.removeEventListener('mouseleave', resetMousePosition);\n }\n };\n },\n [options.resetOnExit]\n );\n\n return { ref: refCallback, ...position };\n}\n\nexport interface UseMousePositionReturnValue {\n x: number;\n y: number;\n}\n\nexport function useMousePosition(): UseMousePositionReturnValue {\n const [position, setPosition] = useState({ x: 0, y: 0 });\n\n useEffect(() => {\n const setMousePosition = (event: MouseEvent) => {\n setPosition({ x: event.clientX, y: event.clientY });\n };\n\n document.addEventListener('mousemove', setMousePosition);\n\n return () => {\n document.removeEventListener('mousemove', setMousePosition);\n };\n }, []);\n\n return position;\n}\n\nexport namespace useMouse {\n export type ReturnValue<T extends HTMLElement> = UseMouseReturnValue<T>;\n}\n\nexport namespace useMousePosition {\n export type ReturnValue = UseMousePositionReturnValue;\n}\n"],"mappings":";;;AAQA,SAAgB,SACd,UAAqC,EAAE,aAAa,OAAO,EACnC;CACxB,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,UAAwB;EAAE,GAAG;EAAG,GAAG;EAAG,CAAC;AAoCxD,QAAO;EAAE,MAAA,GAAA,MAAA,cAjCN,SAAS;GACR,MAAM,oBAAoB,UAAiB;IACzC,MAAM,aAAa;AACnB,QAAI,MAAM;KACR,MAAM,OAAO,KAAK,uBAAuB;AAMzC,iBAAY;MAAE,GAJJ,KAAK,IAAI,GAAG,KAAK,MAAM,WAAW,UAAU,KAAK,KAAK,CAAC;MAIhD,GAFP,KAAK,IAAI,GAAG,KAAK,MAAM,WAAW,UAAU,KAAK,IAAI,CAAC;MAE5C,CAAC;UAErB,aAAY;KAAE,GAAG,WAAW;KAAS,GAAG,WAAW;KAAS,CAAC;;GAIjE,MAAM,2BAA2B,YAAY;IAAE,GAAG;IAAG,GAAG;IAAG,CAAC;AAE5D,SAAM,iBAAiB,aAAa,iBAAiB;AACrD,OAAI,QAAQ,YACV,OAAM,iBAAiB,cAAc,mBAAmB;AAG1D,gBAAa;AACX,UAAM,oBAAoB,aAAa,iBAAiB;AACxD,QAAI,QAAQ,YACV,OAAM,oBAAoB,cAAc,mBAAmB;;KAIjE,CAAC,QAAQ,YAAY,CACtB;EAE0B,GAAG;EAAU;;AAQ1C,SAAgB,mBAAgD;CAC9D,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,UAAwB;EAAE,GAAG;EAAG,GAAG;EAAG,CAAC;AAExD,EAAA,GAAA,MAAA,iBAAgB;EACd,MAAM,oBAAoB,UAAsB;AAC9C,eAAY;IAAE,GAAG,MAAM;IAAS,GAAG,MAAM;IAAS,CAAC;;AAGrD,WAAS,iBAAiB,aAAa,iBAAiB;AAExD,eAAa;AACX,YAAS,oBAAoB,aAAa,iBAAiB;;IAE5D,EAAE,CAAC;AAEN,QAAO"}
@@ -12,9 +12,13 @@ function useMove(onChange, handlers, dir = "ltr") {
12
12
  const mounted = (0, react.useRef)(false);
13
13
  const isSliding = (0, react.useRef)(false);
14
14
  const frame = (0, react.useRef)(0);
15
+ const cleanupRef = (0, react.useRef)(null);
15
16
  const [active, setActive] = (0, react.useState)(false);
16
17
  (0, react.useEffect)(() => {
17
18
  mounted.current = true;
19
+ return () => {
20
+ cleanupRef.current?.();
21
+ };
18
22
  }, []);
19
23
  return {
20
24
  ref: (0, react.useCallback)((node) => {
@@ -87,6 +91,10 @@ function useMove(onChange, handlers, dir = "ltr") {
87
91
  };
88
92
  node?.addEventListener("mousedown", onMouseDown);
89
93
  node?.addEventListener("touchstart", onTouchStart, { passive: false });
94
+ cleanupRef.current = () => {
95
+ unbindEvents();
96
+ cancelAnimationFrame(frame.current);
97
+ };
90
98
  return () => {
91
99
  if (node) {
92
100
  node.removeEventListener("mousedown", onMouseDown);
@@ -1 +1 @@
1
- {"version":3,"file":"use-move.cjs","names":["clamp"],"sources":["../../src/use-move/use-move.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { clamp } from '../utils';\n\nexport interface UseMovePosition {\n x: number;\n y: number;\n}\n\nexport function clampUseMovePosition(position: UseMovePosition) {\n return {\n x: clamp(position.x, 0, 1),\n y: clamp(position.y, 0, 1),\n };\n}\n\nexport interface UseMoveHandlers {\n onScrubStart?: () => void;\n onScrubEnd?: () => void;\n}\n\nexport interface UseMoveReturnValue<T extends HTMLElement = any> {\n ref: React.RefCallback<T | null>;\n active: boolean;\n}\n\nexport function useMove<T extends HTMLElement = any>(\n onChange: (value: UseMovePosition) => void,\n handlers?: UseMoveHandlers,\n dir: 'ltr' | 'rtl' = 'ltr'\n): UseMoveReturnValue<T> {\n const mounted = useRef<boolean>(false);\n const isSliding = useRef(false);\n const frame = useRef(0);\n const [active, setActive] = useState(false);\n\n useEffect(() => {\n mounted.current = true;\n }, []);\n\n const refCallback: React.RefCallback<T | null> = useCallback(\n (node) => {\n const onScrub = ({ x, y }: UseMovePosition) => {\n cancelAnimationFrame(frame.current);\n\n frame.current = requestAnimationFrame(() => {\n if (mounted.current && node) {\n node.style.userSelect = 'none';\n const rect = node.getBoundingClientRect();\n\n if (rect.width && rect.height) {\n const _x = clamp((x - rect.left) / rect.width, 0, 1);\n onChange({\n x: dir === 'ltr' ? _x : 1 - _x,\n y: clamp((y - rect.top) / rect.height, 0, 1),\n });\n }\n }\n });\n };\n\n const bindEvents = () => {\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', stopScrubbing);\n document.addEventListener('touchmove', onTouchMove, { passive: false });\n document.addEventListener('touchend', stopScrubbing);\n };\n\n const unbindEvents = () => {\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', stopScrubbing);\n document.removeEventListener('touchmove', onTouchMove);\n document.removeEventListener('touchend', stopScrubbing);\n };\n\n const startScrubbing = () => {\n if (!isSliding.current && mounted.current) {\n isSliding.current = true;\n typeof handlers?.onScrubStart === 'function' && handlers.onScrubStart();\n setActive(true);\n bindEvents();\n }\n };\n\n const stopScrubbing = () => {\n if (isSliding.current && mounted.current) {\n isSliding.current = false;\n setActive(false);\n unbindEvents();\n setTimeout(() => {\n typeof handlers?.onScrubEnd === 'function' && handlers.onScrubEnd();\n }, 0);\n }\n };\n\n const onMouseDown = (event: MouseEvent) => {\n startScrubbing();\n event.preventDefault();\n onMouseMove(event);\n };\n\n const onMouseMove = (event: MouseEvent) => onScrub({ x: event.clientX, y: event.clientY });\n\n const onTouchStart = (event: TouchEvent) => {\n if (event.cancelable) {\n event.preventDefault();\n }\n\n startScrubbing();\n onTouchMove(event);\n };\n\n const onTouchMove = (event: TouchEvent) => {\n if (event.cancelable) {\n event.preventDefault();\n }\n\n onScrub({ x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY });\n };\n\n node?.addEventListener('mousedown', onMouseDown);\n node?.addEventListener('touchstart', onTouchStart, { passive: false });\n\n return () => {\n if (node) {\n node.removeEventListener('mousedown', onMouseDown);\n node.removeEventListener('touchstart', onTouchStart);\n }\n };\n },\n [dir, onChange]\n );\n\n return { ref: refCallback, active };\n}\n\nexport namespace useMove {\n export type Handlers = UseMoveHandlers;\n export type ReturnValue<T extends HTMLElement> = UseMoveReturnValue<T>;\n}\n"],"mappings":";;;;AAQA,SAAgB,qBAAqB,UAA2B;AAC9D,QAAO;EACL,GAAGA,cAAAA,MAAM,SAAS,GAAG,GAAG,EAAE;EAC1B,GAAGA,cAAAA,MAAM,SAAS,GAAG,GAAG,EAAE;EAC3B;;AAaH,SAAgB,QACd,UACA,UACA,MAAqB,OACE;CACvB,MAAM,WAAA,GAAA,MAAA,QAA0B,MAAM;CACtC,MAAM,aAAA,GAAA,MAAA,QAAmB,MAAM;CAC/B,MAAM,SAAA,GAAA,MAAA,QAAe,EAAE;CACvB,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,UAAsB,MAAM;AAE3C,EAAA,GAAA,MAAA,iBAAgB;AACd,UAAQ,UAAU;IACjB,EAAE,CAAC;AA+FN,QAAO;EAAE,MAAA,GAAA,MAAA,cA5FN,SAAS;GACR,MAAM,WAAW,EAAE,GAAG,QAAyB;AAC7C,yBAAqB,MAAM,QAAQ;AAEnC,UAAM,UAAU,4BAA4B;AAC1C,SAAI,QAAQ,WAAW,MAAM;AAC3B,WAAK,MAAM,aAAa;MACxB,MAAM,OAAO,KAAK,uBAAuB;AAEzC,UAAI,KAAK,SAAS,KAAK,QAAQ;OAC7B,MAAM,KAAKA,cAAAA,OAAO,IAAI,KAAK,QAAQ,KAAK,OAAO,GAAG,EAAE;AACpD,gBAAS;QACP,GAAG,QAAQ,QAAQ,KAAK,IAAI;QAC5B,GAAGA,cAAAA,OAAO,IAAI,KAAK,OAAO,KAAK,QAAQ,GAAG,EAAE;QAC7C,CAAC;;;MAGN;;GAGJ,MAAM,mBAAmB;AACvB,aAAS,iBAAiB,aAAa,YAAY;AACnD,aAAS,iBAAiB,WAAW,cAAc;AACnD,aAAS,iBAAiB,aAAa,aAAa,EAAE,SAAS,OAAO,CAAC;AACvE,aAAS,iBAAiB,YAAY,cAAc;;GAGtD,MAAM,qBAAqB;AACzB,aAAS,oBAAoB,aAAa,YAAY;AACtD,aAAS,oBAAoB,WAAW,cAAc;AACtD,aAAS,oBAAoB,aAAa,YAAY;AACtD,aAAS,oBAAoB,YAAY,cAAc;;GAGzD,MAAM,uBAAuB;AAC3B,QAAI,CAAC,UAAU,WAAW,QAAQ,SAAS;AACzC,eAAU,UAAU;AACpB,YAAO,UAAU,iBAAiB,cAAc,SAAS,cAAc;AACvE,eAAU,KAAK;AACf,iBAAY;;;GAIhB,MAAM,sBAAsB;AAC1B,QAAI,UAAU,WAAW,QAAQ,SAAS;AACxC,eAAU,UAAU;AACpB,eAAU,MAAM;AAChB,mBAAc;AACd,sBAAiB;AACf,aAAO,UAAU,eAAe,cAAc,SAAS,YAAY;QAClE,EAAE;;;GAIT,MAAM,eAAe,UAAsB;AACzC,oBAAgB;AAChB,UAAM,gBAAgB;AACtB,gBAAY,MAAM;;GAGpB,MAAM,eAAe,UAAsB,QAAQ;IAAE,GAAG,MAAM;IAAS,GAAG,MAAM;IAAS,CAAC;GAE1F,MAAM,gBAAgB,UAAsB;AAC1C,QAAI,MAAM,WACR,OAAM,gBAAgB;AAGxB,oBAAgB;AAChB,gBAAY,MAAM;;GAGpB,MAAM,eAAe,UAAsB;AACzC,QAAI,MAAM,WACR,OAAM,gBAAgB;AAGxB,YAAQ;KAAE,GAAG,MAAM,eAAe,GAAG;KAAS,GAAG,MAAM,eAAe,GAAG;KAAS,CAAC;;AAGrF,SAAM,iBAAiB,aAAa,YAAY;AAChD,SAAM,iBAAiB,cAAc,cAAc,EAAE,SAAS,OAAO,CAAC;AAEtE,gBAAa;AACX,QAAI,MAAM;AACR,UAAK,oBAAoB,aAAa,YAAY;AAClD,UAAK,oBAAoB,cAAc,aAAa;;;KAI1D,CAAC,KAAK,SAAS,CAChB;EAE0B;EAAQ"}
1
+ {"version":3,"file":"use-move.cjs","names":["clamp"],"sources":["../../src/use-move/use-move.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { clamp } from '../utils';\n\nexport interface UseMovePosition {\n x: number;\n y: number;\n}\n\nexport function clampUseMovePosition(position: UseMovePosition) {\n return {\n x: clamp(position.x, 0, 1),\n y: clamp(position.y, 0, 1),\n };\n}\n\nexport interface UseMoveHandlers {\n onScrubStart?: () => void;\n onScrubEnd?: () => void;\n}\n\nexport interface UseMoveReturnValue<T extends HTMLElement = any> {\n ref: React.RefCallback<T | null>;\n active: boolean;\n}\n\nexport function useMove<T extends HTMLElement = any>(\n onChange: (value: UseMovePosition) => void,\n handlers?: UseMoveHandlers,\n dir: 'ltr' | 'rtl' = 'ltr'\n): UseMoveReturnValue<T> {\n const mounted = useRef<boolean>(false);\n const isSliding = useRef(false);\n const frame = useRef(0);\n const cleanupRef = useRef<(() => void) | null>(null);\n const [active, setActive] = useState(false);\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n cleanupRef.current?.();\n };\n }, []);\n\n const refCallback: React.RefCallback<T | null> = useCallback(\n (node) => {\n const onScrub = ({ x, y }: UseMovePosition) => {\n cancelAnimationFrame(frame.current);\n\n frame.current = requestAnimationFrame(() => {\n if (mounted.current && node) {\n node.style.userSelect = 'none';\n const rect = node.getBoundingClientRect();\n\n if (rect.width && rect.height) {\n const _x = clamp((x - rect.left) / rect.width, 0, 1);\n onChange({\n x: dir === 'ltr' ? _x : 1 - _x,\n y: clamp((y - rect.top) / rect.height, 0, 1),\n });\n }\n }\n });\n };\n\n const bindEvents = () => {\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', stopScrubbing);\n document.addEventListener('touchmove', onTouchMove, { passive: false });\n document.addEventListener('touchend', stopScrubbing);\n };\n\n const unbindEvents = () => {\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', stopScrubbing);\n document.removeEventListener('touchmove', onTouchMove);\n document.removeEventListener('touchend', stopScrubbing);\n };\n\n const startScrubbing = () => {\n if (!isSliding.current && mounted.current) {\n isSliding.current = true;\n typeof handlers?.onScrubStart === 'function' && handlers.onScrubStart();\n setActive(true);\n bindEvents();\n }\n };\n\n const stopScrubbing = () => {\n if (isSliding.current && mounted.current) {\n isSliding.current = false;\n setActive(false);\n unbindEvents();\n setTimeout(() => {\n typeof handlers?.onScrubEnd === 'function' && handlers.onScrubEnd();\n }, 0);\n }\n };\n\n const onMouseDown = (event: MouseEvent) => {\n startScrubbing();\n event.preventDefault();\n onMouseMove(event);\n };\n\n const onMouseMove = (event: MouseEvent) => onScrub({ x: event.clientX, y: event.clientY });\n\n const onTouchStart = (event: TouchEvent) => {\n if (event.cancelable) {\n event.preventDefault();\n }\n\n startScrubbing();\n onTouchMove(event);\n };\n\n const onTouchMove = (event: TouchEvent) => {\n if (event.cancelable) {\n event.preventDefault();\n }\n\n onScrub({ x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY });\n };\n\n node?.addEventListener('mousedown', onMouseDown);\n node?.addEventListener('touchstart', onTouchStart, { passive: false });\n\n cleanupRef.current = () => {\n unbindEvents();\n cancelAnimationFrame(frame.current);\n };\n\n return () => {\n if (node) {\n node.removeEventListener('mousedown', onMouseDown);\n node.removeEventListener('touchstart', onTouchStart);\n }\n };\n },\n [dir, onChange]\n );\n\n return { ref: refCallback, active };\n}\n\nexport namespace useMove {\n export type Handlers = UseMoveHandlers;\n export type ReturnValue<T extends HTMLElement> = UseMoveReturnValue<T>;\n}\n"],"mappings":"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"}