@mantine/hooks 9.3.0 → 9.3.2

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.
@@ -5,7 +5,10 @@ let react = require("react");
5
5
  //#region packages/@mantine/hooks/src/use-id/use-id.ts
6
6
  function useId(staticId) {
7
7
  const [uuid, setUuid] = (0, react.useState)(`mantine-${(0, react.useId)().replace(/:/g, "")}`);
8
+ const hasInitializedRef = (0, react.useRef)(false);
8
9
  require_use_isomorphic_effect.useIsomorphicEffect(() => {
10
+ if (hasInitializedRef.current) return;
11
+ hasInitializedRef.current = true;
9
12
  setUuid(require_random_id.randomId());
10
13
  }, []);
11
14
  if (typeof staticId === "string") return staticId;
@@ -1 +1 @@
1
- {"version":3,"file":"use-id.cjs","names":["randomId"],"sources":["../../src/use-id/use-id.ts"],"sourcesContent":["import { useId as useReactId, 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\n useIsomorphicEffect(() => {\n setUuid(randomId());\n }, []);\n\n if (typeof staticId === 'string') {\n return staticId;\n }\n\n return uuid;\n}\n"],"mappings":";;;;;AAIA,SAAgB,MAAM,UAAmB;CAEvC,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,UAAoB,YAAA,GAAA,MAAA,OAAiB,EAAE,QAAQ,MAAM,EAAE,GAAG;CAEvE,8BAAA,0BAA0B;EACxB,QAAQA,kBAAAA,SAAS,CAAC;CACpB,GAAG,CAAC,CAAC;CAEL,IAAI,OAAO,aAAa,UACtB,OAAO;CAGT,OAAO;AACT"}
1
+ {"version":3,"file":"use-id.cjs","names":["randomId"],"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,SAAgB,MAAM,UAAmB;CAEvC,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,UAAoB,YAAA,GAAA,MAAA,OAAiB,EAAE,QAAQ,MAAM,EAAE,GAAG;CACvE,MAAM,qBAAA,GAAA,MAAA,QAA2B,KAAK;CAEtC,8BAAA,0BAA0B;EACxB,IAAI,kBAAkB,SACpB;EAEF,kBAAkB,UAAU;EAC5B,QAAQA,kBAAAA,SAAS,CAAC;CACpB,GAAG,CAAC,CAAC;CAEL,IAAI,OAAO,aAAa,UACtB,OAAO;CAGT,OAAO;AACT"}
@@ -1,17 +1,23 @@
1
1
  "use client";
2
2
  let react = require("react");
3
3
  //#region packages/@mantine/hooks/src/use-long-press/use-long-press.ts
4
+ const DEFAULT_EVENTS = ["mouse", "touch"];
5
+ const DEFAULT_MOVE_THRESHOLD = 10;
4
6
  function useLongPress(onLongPress, options = {}) {
5
- const { threshold = 400, onStart, onFinish, onCancel } = options;
7
+ const { threshold = 400, events = DEFAULT_EVENTS, cancelOnMove = false, onStart, onFinish, onCancel } = options;
6
8
  const isLongPressActive = (0, react.useRef)(false);
7
9
  const isPressed = (0, react.useRef)(false);
8
10
  const timeout = (0, react.useRef)(-1);
11
+ const startPosition = (0, react.useRef)(null);
9
12
  (0, react.useEffect)(() => () => window.clearTimeout(timeout.current), []);
10
13
  return (0, react.useMemo)(() => {
11
14
  if (typeof onLongPress !== "function") return {};
15
+ const moveEnabled = cancelOnMove !== false;
16
+ const moveThreshold = cancelOnMove === true ? DEFAULT_MOVE_THRESHOLD : cancelOnMove === false ? 0 : cancelOnMove;
12
17
  const start = (event) => {
13
18
  if (!isMouseEvent(event) && !isTouchEvent(event)) return;
14
19
  if (onStart) onStart(event);
20
+ startPosition.current = getEventPosition(event);
15
21
  isPressed.current = true;
16
22
  timeout.current = window.setTimeout(() => {
17
23
  onLongPress(event);
@@ -27,27 +33,57 @@ function useLongPress(onLongPress, options = {}) {
27
33
  }
28
34
  isLongPressActive.current = false;
29
35
  isPressed.current = false;
36
+ startPosition.current = null;
30
37
  if (timeout.current !== -1) {
31
38
  window.clearTimeout(timeout.current);
32
39
  timeout.current = -1;
33
40
  }
34
41
  };
35
- return {
36
- onMouseDown: start,
37
- onMouseUp: cancel,
38
- onMouseLeave: cancel,
39
- onTouchStart: start,
40
- onTouchEnd: cancel,
41
- onTouchCancel: cancel
42
+ const move = (event) => {
43
+ if (!moveEnabled || !isPressed.current || isLongPressActive.current) return;
44
+ const position = getEventPosition(event);
45
+ if (!position || !startPosition.current) return;
46
+ const dx = position.x - startPosition.current.x;
47
+ const dy = position.y - startPosition.current.y;
48
+ if (Math.sqrt(dx * dx + dy * dy) > moveThreshold) cancel(event);
42
49
  };
50
+ const handlers = {};
51
+ if (events.includes("mouse")) {
52
+ handlers.onMouseDown = start;
53
+ handlers.onMouseUp = cancel;
54
+ handlers.onMouseLeave = cancel;
55
+ if (moveEnabled) handlers.onMouseMove = move;
56
+ }
57
+ if (events.includes("touch")) {
58
+ handlers.onTouchStart = start;
59
+ handlers.onTouchEnd = cancel;
60
+ handlers.onTouchCancel = cancel;
61
+ if (moveEnabled) handlers.onTouchMove = move;
62
+ }
63
+ return handlers;
43
64
  }, [
44
65
  onLongPress,
45
66
  threshold,
46
67
  onCancel,
47
68
  onFinish,
48
- onStart
69
+ onStart,
70
+ cancelOnMove,
71
+ events.join(",")
49
72
  ]);
50
73
  }
74
+ function getEventPosition(event) {
75
+ if (isTouchEvent(event)) {
76
+ const touch = event.touches[0] ?? event.changedTouches[0];
77
+ return touch ? {
78
+ x: touch.clientX,
79
+ y: touch.clientY
80
+ } : null;
81
+ }
82
+ return {
83
+ x: event.clientX,
84
+ y: event.clientY
85
+ };
86
+ }
51
87
  function isTouchEvent(event) {
52
88
  return window.TouchEvent ? event.nativeEvent instanceof TouchEvent : "touches" in event.nativeEvent;
53
89
  }
@@ -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 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,CAAC,GACP;CACzB,MAAM,EAAE,YAAY,KAAK,SAAS,UAAU,aAAa;CACzD,MAAM,qBAAA,GAAA,MAAA,QAA2B,KAAK;CACtC,MAAM,aAAA,GAAA,MAAA,QAAmB,KAAK;CAC9B,MAAM,WAAA,GAAA,MAAA,QAAyB,EAAE;CAEjC,CAAA,GAAA,MAAA,uBAAsB,OAAO,aAAa,QAAQ,OAAO,GAAG,CAAC,CAAC;CAE9D,QAAA,GAAA,MAAA,eAAqB;EACnB,IAAI,OAAO,gBAAgB,YACzB,OAAO,CAAC;EAGV,MAAM,SAAS,UAA+C;GAC5D,IAAI,CAAC,aAAa,KAAK,KAAK,CAAC,aAAa,KAAK,GAC7C;GAGF,IAAI,SACF,QAAQ,KAAK;GAGf,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;GAEpB,IAAI,QAAQ,YAAY,IAAI;IAC1B,OAAO,aAAa,QAAQ,OAAO;IACnC,QAAQ,UAAU;GACpB;EACF;EAEA,OAAO;GACL,aAAa;GACb,WAAW;GACX,cAAc;GACd,cAAc;GACd,YAAY;GACZ,eAAe;EACjB;CACF,GAAG;EAAC;EAAa;EAAW;EAAU;EAAU;CAAO,CAAC;AAC1D;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.cjs","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,qBAAA,GAAA,MAAA,QAA2B,KAAK;CACtC,MAAM,aAAA,GAAA,MAAA,QAAmB,KAAK;CAC9B,MAAM,WAAA,GAAA,MAAA,QAAyB,EAAE;CACjC,MAAM,iBAAA,GAAA,MAAA,QAAwD,IAAI;CAElE,CAAA,GAAA,MAAA,uBAAsB,OAAO,aAAa,QAAQ,OAAO,GAAG,CAAC,CAAC;CAI9D,QAAA,GAAA,MAAA,eAAqB;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"}
@@ -198,15 +198,8 @@ function useMask(options) {
198
198
  const opts = optionsRef.current;
199
199
  return getResolvedOptions(opts, rawValue);
200
200
  }, [rawValue]);
201
- const updateValue = (0, react.useCallback)((newMasked, cursorPos) => {
201
+ const applyValue = (0, react.useCallback)(({ reprocessed, newRaw, displayValue, resolvedSlots, cursorPos, notifyChange }) => {
202
202
  const opts = optionsRef.current;
203
- const { slots } = getResolvedOptions(opts, extractRaw(newMasked, getResolvedOptions(opts, "").slots));
204
- const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, extractRaw(newMasked, slots));
205
- const reprocessed = processInput(newMasked, resolvedSlots, slotChar);
206
- const newRaw = extractRaw(reprocessed, resolvedSlots);
207
- const showSlots = opts.alwaysShowMask || isFocusedRef.current;
208
- const showOnFocus = opts.showMaskOnFocus !== false;
209
- const displayValue = buildDisplayValue(reprocessed, resolvedSlots, slotChar, showSlots && (showOnFocus || reprocessed.length > 0));
210
203
  processedRef.current = reprocessed;
211
204
  displayValueRef.current = displayValue;
212
205
  rawValueRef.current = newRaw;
@@ -219,17 +212,53 @@ function useMask(options) {
219
212
  inputRef.current.setSelectionRange(pos, pos);
220
213
  }
221
214
  }
222
- if (opts.onChangeRaw) opts.onChangeRaw(newRaw, displayValue);
215
+ if (notifyChange && opts.onChangeRaw) opts.onChangeRaw(newRaw, displayValue);
223
216
  const complete = checkComplete(reprocessed, resolvedSlots);
224
- if (complete && !wasCompleteRef.current && opts.onComplete) opts.onComplete(displayValue, newRaw);
217
+ if (notifyChange && complete && !wasCompleteRef.current && opts.onComplete) opts.onComplete(displayValue, newRaw);
225
218
  wasCompleteRef.current = complete;
219
+ }, []);
220
+ const updateValue = (0, react.useCallback)((newMasked, cursorPos) => {
221
+ const opts = optionsRef.current;
222
+ const { slots } = getResolvedOptions(opts, extractRaw(newMasked, getResolvedOptions(opts, "").slots));
223
+ const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, extractRaw(newMasked, slots));
224
+ const reprocessed = processInput(newMasked, resolvedSlots, slotChar);
225
+ const newRaw = extractRaw(reprocessed, resolvedSlots);
226
+ const showSlots = opts.alwaysShowMask || isFocusedRef.current;
227
+ const showOnFocus = opts.showMaskOnFocus !== false;
228
+ const displayValue = buildDisplayValue(reprocessed, resolvedSlots, slotChar, showSlots && (showOnFocus || reprocessed.length > 0));
229
+ applyValue({
230
+ reprocessed,
231
+ newRaw,
232
+ displayValue,
233
+ resolvedSlots,
234
+ cursorPos,
235
+ notifyChange: true
236
+ });
226
237
  return {
227
238
  displayValue,
228
239
  newRaw,
229
240
  reprocessed,
230
241
  resolvedSlots
231
242
  };
232
- }, [getOptions]);
243
+ }, [applyValue, getOptions]);
244
+ const initializeInputValue = (0, react.useCallback)((node) => {
245
+ const opts = optionsRef.current;
246
+ if (!node.value) return false;
247
+ const { slots: initialSlots, slotChar: initialSlotChar } = getResolvedOptions(opts, "");
248
+ const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, extractRaw(processInput(node.value, initialSlots, initialSlotChar), initialSlots));
249
+ const reprocessed = processInput(node.value, resolvedSlots, slotChar);
250
+ const newRaw = extractRaw(reprocessed, resolvedSlots);
251
+ const showSlots = opts.alwaysShowMask || isFocusedRef.current;
252
+ const showOnFocus = opts.showMaskOnFocus !== false;
253
+ applyValue({
254
+ reprocessed,
255
+ newRaw,
256
+ displayValue: buildDisplayValue(reprocessed, resolvedSlots, slotChar, showSlots && (showOnFocus || reprocessed.length > 0)),
257
+ resolvedSlots,
258
+ notifyChange: false
259
+ });
260
+ return true;
261
+ }, [applyValue]);
233
262
  const pushUndoState = (0, react.useCallback)(() => {
234
263
  const selectionStart = inputRef.current?.selectionStart ?? rawValueRef.current.length;
235
264
  const state = {
@@ -513,7 +542,8 @@ function useMask(options) {
513
542
  node.addEventListener("keydown", handleKeyDown);
514
543
  node.addEventListener("paste", handlePaste);
515
544
  setAriaAttributes(node);
516
- if (options.alwaysShowMask && !node.value) {
545
+ const hasInitialValue = initializeInputValue(node);
546
+ if (options.alwaysShowMask && !hasInitialValue) {
517
547
  const { slots, slotChar } = getResolvedOptions(options, "");
518
548
  const display = buildDisplayValue("", slots, slotChar, true);
519
549
  node.value = display;
@@ -529,6 +559,7 @@ function useMask(options) {
529
559
  handleMouseUp,
530
560
  handleKeyDown,
531
561
  handlePaste,
562
+ initializeInputValue,
532
563
  setAriaAttributes,
533
564
  options
534
565
  ]);
@@ -1 +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\ninterface UndoState {\n rawValue: string;\n selectionStart: number;\n}\n\nconst MAX_UNDO_HISTORY = 100;\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 displayValueRef = useRef('');\n const rawValueRef = useRef('');\n const wasCompleteRef = useRef(false);\n const isFocusedRef = useRef(false);\n const undoStackRef = useRef<UndoState[]>([]);\n const redoStackRef = useRef<UndoState[]>([]);\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 displayValueRef.current = displayValue;\n rawValueRef.current = newRaw;\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 pushUndoState = useCallback(() => {\n const input = inputRef.current;\n const selectionStart = input?.selectionStart ?? rawValueRef.current.length;\n const state: UndoState = {\n rawValue: rawValueRef.current,\n selectionStart,\n };\n const stack = undoStackRef.current;\n const top = stack[stack.length - 1];\n if (top && top.rawValue === state.rawValue && top.selectionStart === state.selectionStart) {\n return;\n }\n stack.push(state);\n if (stack.length > MAX_UNDO_HISTORY) {\n stack.shift();\n }\n redoStackRef.current = [];\n }, []);\n\n const applyHistoryState = useCallback(\n (target: UndoState) => {\n const opts = optionsRef.current;\n const { slots, slotChar, transform } = getResolvedOptions(opts, target.rawValue);\n const newMasked = applyMaskToRaw(target.rawValue, slots, slotChar, transform);\n updateValue(newMasked, target.selectionStart);\n },\n [updateValue]\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 prev = displayValueRef.current;\n const curr = input.value;\n\n let prefixLen = 0;\n const maxPrefix = Math.min(prev.length, curr.length);\n while (prefixLen < maxPrefix && prev[prefixLen] === curr[prefixLen]) {\n prefixLen++;\n }\n\n let suffixLen = 0;\n const maxSuffix = Math.min(prev.length - prefixLen, curr.length - prefixLen);\n while (\n suffixLen < maxSuffix &&\n prev[prev.length - 1 - suffixLen] === curr[curr.length - 1 - suffixLen]\n ) {\n suffixLen++;\n }\n\n const insertedText = curr.slice(prefixLen, curr.length - suffixLen);\n const removedEnd = prev.length - suffixLen;\n\n const beforeRaw = extractRaw(prev.slice(0, prefixLen), resolvedSlots.slice(0, prefixLen));\n const afterRaw = extractRaw(prev.slice(removedEnd), resolvedSlots.slice(removedEnd));\n const reformatted = applyMaskToRaw(\n beforeRaw + insertedText + afterRaw,\n resolvedSlots,\n slotChar,\n transform\n );\n const maskedPrefix = applyMaskToRaw(\n beforeRaw + insertedText,\n resolvedSlots,\n slotChar,\n transform\n );\n\n if (reformatted !== prev) {\n pushUndoState();\n }\n updateValue(reformatted, maskedPrefix.length);\n },\n [pushUndoState, updateValue]\n );\n\n const clampCursorToProcessed = useCallback((input: HTMLInputElement) => {\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end) {\n return;\n }\n\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(opts, '');\n const processed = processedRef.current;\n const endPos =\n processed.length > 0\n ? findNextEditablePosition(processed.length, slots, processed)\n : findNextTokenIndex(slots, 0);\n const startPos = findNextTokenIndex(slots, 0);\n\n if (start > endPos || start < startPos) {\n input.setSelectionRange(endPos, endPos);\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 displayValueRef.current = 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 handleMouseDown = useCallback(() => {\n const input = inputRef.current;\n if (!input) {\n return;\n }\n\n requestAnimationFrame(() => {\n if (input !== document.activeElement) {\n return;\n }\n\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end) {\n return;\n }\n\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(opts, '');\n const processed = processedRef.current;\n const endPos =\n processed.length > 0\n ? findNextEditablePosition(processed.length, slots, processed)\n : findNextTokenIndex(slots, 0);\n\n if (start > endPos) {\n input.setSelectionRange(endPos, endPos);\n }\n });\n }, []);\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 expectedFocusDisplay = buildDisplayValue(processedRef.current, slots, slotChar, true);\n const processed =\n input.value === expectedFocusDisplay\n ? processedRef.current\n : 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 displayValueRef.current = '';\n rawValueRef.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 displayValueRef.current = emptyDisplay;\n setMaskedValue(emptyDisplay);\n }\n return;\n }\n\n if (!opts.alwaysShowMask && !complete) {\n if (extractRaw(processed, slots).length === 0) {\n input.value = '';\n processedRef.current = '';\n displayValueRef.current = '';\n rawValueRef.current = '';\n setMaskedValue('');\n setRawValue('');\n wasCompleteRef.current = false;\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw('', '');\n }\n return;\n }\n\n const display = buildDisplayValue(processed, slots, slotChar, false);\n input.value = display;\n displayValueRef.current = 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 const modifier = e.metaKey || (e.ctrlKey && !e.altKey);\n const key = e.key.toLowerCase();\n\n if (modifier && key === 'z' && !e.shiftKey) {\n e.preventDefault();\n const prev = undoStackRef.current.pop();\n if (!prev) {\n return;\n }\n redoStackRef.current.push({\n rawValue: rawValueRef.current,\n selectionStart: input.selectionStart ?? 0,\n });\n applyHistoryState(prev);\n return;\n }\n\n if (modifier && ((key === 'z' && e.shiftKey) || (key === 'y' && !e.shiftKey))) {\n e.preventDefault();\n const next = redoStackRef.current.pop();\n if (!next) {\n return;\n }\n undoStackRef.current.push({\n rawValue: rawValueRef.current,\n selectionStart: input.selectionStart ?? 0,\n });\n applyHistoryState(next);\n return;\n }\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 pushUndoState();\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 pushUndoState();\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 pushUndoState();\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 pushUndoState();\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 pushUndoState();\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 pushUndoState();\n updateValue(newValue, newCursorPos);\n }\n },\n [applyHistoryState, pushUndoState, 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 clampedStart = Math.min(start, processed.length);\n const clampedEnd = Math.min(end, processed.length);\n const beforeRaw = extractRaw(processed.slice(0, clampedStart), slots.slice(0, clampedStart));\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 pushUndoState();\n updateValue(newValue);\n\n const maskedPrefix = applyMaskToRaw(beforeRaw + pastedText, slots, slotChar, transform);\n const pasteEndPos = Math.min(maskedPrefix.length, slots.length);\n if (input === document.activeElement) {\n input.setSelectionRange(pasteEndPos, pasteEndPos);\n }\n },\n [pushUndoState, 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('mousedown', handleMouseDown);\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('mousedown', handleMouseDown);\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 displayValueRef.current = display;\n setMaskedValue(display);\n }\n }\n },\n [\n handleInput,\n handleFocus,\n handleBlur,\n handleMouseDown,\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 displayValueRef.current = '';\n rawValueRef.current = '';\n undoStackRef.current = [];\n redoStackRef.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 displayValueRef.current = 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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"}
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\ninterface UndoState {\n rawValue: string;\n selectionStart: number;\n}\n\nconst MAX_UNDO_HISTORY = 100;\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 displayValueRef = useRef('');\n const rawValueRef = useRef('');\n const wasCompleteRef = useRef(false);\n const isFocusedRef = useRef(false);\n const undoStackRef = useRef<UndoState[]>([]);\n const redoStackRef = useRef<UndoState[]>([]);\n\n const getOptions = useCallback(() => {\n const opts = optionsRef.current;\n return getResolvedOptions(opts, rawValue);\n }, [rawValue]);\n\n const applyValue = useCallback(\n ({\n reprocessed,\n newRaw,\n displayValue,\n resolvedSlots,\n cursorPos,\n notifyChange,\n }: {\n reprocessed: string;\n newRaw: string;\n displayValue: string;\n resolvedSlots: MaskSlot[];\n cursorPos?: number;\n notifyChange: boolean;\n }) => {\n const opts = optionsRef.current;\n\n processedRef.current = reprocessed;\n displayValueRef.current = displayValue;\n rawValueRef.current = newRaw;\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 (notifyChange && opts.onChangeRaw) {\n opts.onChangeRaw(newRaw, displayValue);\n }\n\n const complete = checkComplete(reprocessed, resolvedSlots);\n if (notifyChange && complete && !wasCompleteRef.current && opts.onComplete) {\n opts.onComplete(displayValue, newRaw);\n }\n wasCompleteRef.current = complete;\n },\n []\n );\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 applyValue({\n reprocessed,\n newRaw,\n displayValue,\n resolvedSlots,\n cursorPos,\n notifyChange: true,\n });\n\n return { displayValue, newRaw, reprocessed, resolvedSlots };\n },\n [applyValue, getOptions]\n );\n\n const initializeInputValue = useCallback(\n (node: HTMLInputElement) => {\n const opts = optionsRef.current;\n\n if (!node.value) {\n return false;\n }\n\n const { slots: initialSlots, slotChar: initialSlotChar } = getResolvedOptions(opts, '');\n const initialProcessed = processInput(node.value, initialSlots, initialSlotChar);\n const initialRaw = extractRaw(initialProcessed, initialSlots);\n const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, initialRaw);\n const reprocessed = processInput(node.value, resolvedSlots, slotChar);\n const newRaw = extractRaw(reprocessed, resolvedSlots);\n const showSlots = opts.alwaysShowMask || isFocusedRef.current;\n const showOnFocus = opts.showMaskOnFocus !== false;\n const shouldShowSlots = showSlots && (showOnFocus || reprocessed.length > 0);\n const displayValue = buildDisplayValue(reprocessed, resolvedSlots, slotChar, shouldShowSlots);\n\n applyValue({\n reprocessed,\n newRaw,\n displayValue,\n resolvedSlots,\n notifyChange: false,\n });\n\n return true;\n },\n [applyValue]\n );\n\n const pushUndoState = useCallback(() => {\n const input = inputRef.current;\n const selectionStart = input?.selectionStart ?? rawValueRef.current.length;\n const state: UndoState = {\n rawValue: rawValueRef.current,\n selectionStart,\n };\n const stack = undoStackRef.current;\n const top = stack[stack.length - 1];\n if (top && top.rawValue === state.rawValue && top.selectionStart === state.selectionStart) {\n return;\n }\n stack.push(state);\n if (stack.length > MAX_UNDO_HISTORY) {\n stack.shift();\n }\n redoStackRef.current = [];\n }, []);\n\n const applyHistoryState = useCallback(\n (target: UndoState) => {\n const opts = optionsRef.current;\n const { slots, slotChar, transform } = getResolvedOptions(opts, target.rawValue);\n const newMasked = applyMaskToRaw(target.rawValue, slots, slotChar, transform);\n updateValue(newMasked, target.selectionStart);\n },\n [updateValue]\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 prev = displayValueRef.current;\n const curr = input.value;\n\n let prefixLen = 0;\n const maxPrefix = Math.min(prev.length, curr.length);\n while (prefixLen < maxPrefix && prev[prefixLen] === curr[prefixLen]) {\n prefixLen++;\n }\n\n let suffixLen = 0;\n const maxSuffix = Math.min(prev.length - prefixLen, curr.length - prefixLen);\n while (\n suffixLen < maxSuffix &&\n prev[prev.length - 1 - suffixLen] === curr[curr.length - 1 - suffixLen]\n ) {\n suffixLen++;\n }\n\n const insertedText = curr.slice(prefixLen, curr.length - suffixLen);\n const removedEnd = prev.length - suffixLen;\n\n const beforeRaw = extractRaw(prev.slice(0, prefixLen), resolvedSlots.slice(0, prefixLen));\n const afterRaw = extractRaw(prev.slice(removedEnd), resolvedSlots.slice(removedEnd));\n const reformatted = applyMaskToRaw(\n beforeRaw + insertedText + afterRaw,\n resolvedSlots,\n slotChar,\n transform\n );\n const maskedPrefix = applyMaskToRaw(\n beforeRaw + insertedText,\n resolvedSlots,\n slotChar,\n transform\n );\n\n if (reformatted !== prev) {\n pushUndoState();\n }\n updateValue(reformatted, maskedPrefix.length);\n },\n [pushUndoState, updateValue]\n );\n\n const clampCursorToProcessed = useCallback((input: HTMLInputElement) => {\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end) {\n return;\n }\n\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(opts, '');\n const processed = processedRef.current;\n const endPos =\n processed.length > 0\n ? findNextEditablePosition(processed.length, slots, processed)\n : findNextTokenIndex(slots, 0);\n const startPos = findNextTokenIndex(slots, 0);\n\n if (start > endPos || start < startPos) {\n input.setSelectionRange(endPos, endPos);\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 displayValueRef.current = 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 handleMouseDown = useCallback(() => {\n const input = inputRef.current;\n if (!input) {\n return;\n }\n\n requestAnimationFrame(() => {\n if (input !== document.activeElement) {\n return;\n }\n\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end) {\n return;\n }\n\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(opts, '');\n const processed = processedRef.current;\n const endPos =\n processed.length > 0\n ? findNextEditablePosition(processed.length, slots, processed)\n : findNextTokenIndex(slots, 0);\n\n if (start > endPos) {\n input.setSelectionRange(endPos, endPos);\n }\n });\n }, []);\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 expectedFocusDisplay = buildDisplayValue(processedRef.current, slots, slotChar, true);\n const processed =\n input.value === expectedFocusDisplay\n ? processedRef.current\n : 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 displayValueRef.current = '';\n rawValueRef.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 displayValueRef.current = emptyDisplay;\n setMaskedValue(emptyDisplay);\n }\n return;\n }\n\n if (!opts.alwaysShowMask && !complete) {\n if (extractRaw(processed, slots).length === 0) {\n input.value = '';\n processedRef.current = '';\n displayValueRef.current = '';\n rawValueRef.current = '';\n setMaskedValue('');\n setRawValue('');\n wasCompleteRef.current = false;\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw('', '');\n }\n return;\n }\n\n const display = buildDisplayValue(processed, slots, slotChar, false);\n input.value = display;\n displayValueRef.current = 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 const modifier = e.metaKey || (e.ctrlKey && !e.altKey);\n const key = e.key.toLowerCase();\n\n if (modifier && key === 'z' && !e.shiftKey) {\n e.preventDefault();\n const prev = undoStackRef.current.pop();\n if (!prev) {\n return;\n }\n redoStackRef.current.push({\n rawValue: rawValueRef.current,\n selectionStart: input.selectionStart ?? 0,\n });\n applyHistoryState(prev);\n return;\n }\n\n if (modifier && ((key === 'z' && e.shiftKey) || (key === 'y' && !e.shiftKey))) {\n e.preventDefault();\n const next = redoStackRef.current.pop();\n if (!next) {\n return;\n }\n undoStackRef.current.push({\n rawValue: rawValueRef.current,\n selectionStart: input.selectionStart ?? 0,\n });\n applyHistoryState(next);\n return;\n }\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 pushUndoState();\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 pushUndoState();\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 pushUndoState();\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 pushUndoState();\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 pushUndoState();\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 pushUndoState();\n updateValue(newValue, newCursorPos);\n }\n },\n [applyHistoryState, pushUndoState, 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 clampedStart = Math.min(start, processed.length);\n const clampedEnd = Math.min(end, processed.length);\n const beforeRaw = extractRaw(processed.slice(0, clampedStart), slots.slice(0, clampedStart));\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 pushUndoState();\n updateValue(newValue);\n\n const maskedPrefix = applyMaskToRaw(beforeRaw + pastedText, slots, slotChar, transform);\n const pasteEndPos = Math.min(maskedPrefix.length, slots.length);\n if (input === document.activeElement) {\n input.setSelectionRange(pasteEndPos, pasteEndPos);\n }\n },\n [pushUndoState, 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('mousedown', handleMouseDown);\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('mousedown', handleMouseDown);\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 const hasInitialValue = initializeInputValue(node);\n\n if (options.alwaysShowMask && !hasInitialValue) {\n const { slots, slotChar } = getResolvedOptions(options, '');\n const display = buildDisplayValue('', slots, slotChar, true);\n node.value = display;\n displayValueRef.current = display;\n setMaskedValue(display);\n }\n }\n },\n [\n handleInput,\n handleFocus,\n handleBlur,\n handleMouseDown,\n handleMouseUp,\n handleKeyDown,\n handlePaste,\n initializeInputValue,\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 displayValueRef.current = '';\n rawValueRef.current = '';\n undoStackRef.current = [];\n redoStackRef.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 displayValueRef.current = 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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"}
@@ -164,7 +164,7 @@ function applyConstraints(sizes, panels, handleIndex, delta, redistribute) {
164
164
  return applyAdjacentOnly(sizes, panels, handleIndex, delta);
165
165
  }
166
166
  function useSplitter(options) {
167
- const { panels, orientation = "horizontal", sizes: controlledSizes, onSizeChange, onCollapseChange, redistribute, step = 1, shiftStep = 10, dir = "ltr", enabled = true } = options;
167
+ const { panels, orientation = "horizontal", sizes: controlledSizes, onSizeChange, onCollapseChange, redistribute, step = 1, shiftStep = 10, dir = "ltr", resetOnDoubleClick = true, enabled = true } = options;
168
168
  const defaultSizes = panels.map((p) => p.defaultSize);
169
169
  const [currentSizes, setCurrentSizes] = require_use_uncontrolled.useUncontrolled({
170
170
  value: controlledSizes,
@@ -227,6 +227,30 @@ function useSplitter(options) {
227
227
  if (currentSizesRef.current[panelIndex] === 0) expandPanel(panelIndex);
228
228
  else collapsePanel(panelIndex);
229
229
  }, [collapsePanel, expandPanel]);
230
+ const emitCollapseTransitions = (0, react.useCallback)((prev, next, indices, preCollapseSnapshot) => {
231
+ const onChange = optionsRef.current.onCollapseChange;
232
+ for (const idx of indices) {
233
+ const wasCollapsed = prev[idx] === 0;
234
+ const nowCollapsed = next[idx] === 0;
235
+ if (!wasCollapsed && nowCollapsed) {
236
+ preCollapseSizesRef.current = [...preCollapseSnapshot];
237
+ onChange?.(idx, true);
238
+ } else if (wasCollapsed && !nowCollapsed) onChange?.(idx, false);
239
+ }
240
+ }, []);
241
+ const reset = (0, react.useCallback)((handleIndex) => {
242
+ const prev = currentSizesRef.current;
243
+ const currentPanels = optionsRef.current.panels;
244
+ const beforeIdx = handleIndex;
245
+ const afterIdx = handleIndex + 1;
246
+ if (beforeIdx < 0 || afterIdx >= prev.length) return;
247
+ const total = prev[beforeIdx] + prev[afterIdx];
248
+ const defBefore = currentPanels[beforeIdx].defaultSize;
249
+ const defTotal = defBefore + currentPanels[afterIdx].defaultSize;
250
+ const next = applyAdjacentOnly(prev, currentPanels, beforeIdx, (defTotal === 0 ? total / 2 : total * (defBefore / defTotal)) - prev[beforeIdx]);
251
+ emitCollapseTransitions(prev, next, [beforeIdx, afterIdx], prev);
252
+ updateSizes(next);
253
+ }, [emitCollapseTransitions, updateSizes]);
230
254
  const containerRefCallback = (0, react.useCallback)((node) => {
231
255
  containerRef.current = node;
232
256
  }, []);
@@ -281,18 +305,7 @@ function useSplitter(options) {
281
305
  const opts = optionsRef.current;
282
306
  const newSizes = applyConstraints(s.startSizes, opts.panels, s.handleIndex, percentDelta, opts.redistribute);
283
307
  const prevSizes = currentSizesRef.current;
284
- const beforeWasCollapsed = prevSizes[s.handleIndex] === 0;
285
- const afterWasCollapsed = prevSizes[s.handleIndex + 1] === 0;
286
- const beforeNowCollapsed = newSizes[s.handleIndex] === 0;
287
- const afterNowCollapsed = newSizes[s.handleIndex + 1] === 0;
288
- if (!beforeWasCollapsed && beforeNowCollapsed) {
289
- preCollapseSizesRef.current = [...s.startSizes];
290
- opts.onCollapseChange?.(s.handleIndex, true);
291
- } else if (beforeWasCollapsed && !beforeNowCollapsed) opts.onCollapseChange?.(s.handleIndex, false);
292
- if (!afterWasCollapsed && afterNowCollapsed) {
293
- preCollapseSizesRef.current = [...s.startSizes];
294
- opts.onCollapseChange?.(s.handleIndex + 1, true);
295
- } else if (afterWasCollapsed && !afterNowCollapsed) opts.onCollapseChange?.(s.handleIndex + 1, false);
308
+ emitCollapseTransitions(prevSizes, newSizes, [s.handleIndex, s.handleIndex + 1], s.startSizes);
296
309
  currentSizesRef.current = newSizes;
297
310
  setCurrentSizes(newSizes);
298
311
  };
@@ -392,21 +405,14 @@ function useSplitter(options) {
392
405
  event.preventDefault();
393
406
  if (delta !== 0) {
394
407
  const newSizes = applyConstraints(currentSizes, panels, index, delta, redistribute);
395
- const beforeWas = currentSizes[index] === 0;
396
- const afterWas = currentSizes[index + 1] === 0;
397
- const beforeNow = newSizes[index] === 0;
398
- const afterNow = newSizes[index + 1] === 0;
399
- if (!beforeWas && beforeNow) {
400
- preCollapseSizesRef.current = [...currentSizes];
401
- onCollapseChange?.(index, true);
402
- } else if (beforeWas && !beforeNow) onCollapseChange?.(index, false);
403
- if (!afterWas && afterNow) {
404
- preCollapseSizesRef.current = [...currentSizes];
405
- onCollapseChange?.(index + 1, true);
406
- } else if (afterWas && !afterNow) onCollapseChange?.(index + 1, false);
408
+ emitCollapseTransitions(currentSizes, newSizes, [index, index + 1], currentSizes);
407
409
  updateSizes(newSizes);
408
410
  }
409
411
  },
412
+ onDoubleClick: () => {
413
+ if (!enabled || !resetOnDoubleClick) return;
414
+ reset(index);
415
+ },
410
416
  "data-active": activeHandle === index || void 0,
411
417
  "data-orientation": orient
412
418
  };
@@ -418,12 +424,14 @@ function useSplitter(options) {
418
424
  dir,
419
425
  step,
420
426
  shiftStep,
427
+ resetOnDoubleClick,
421
428
  activeHandle,
422
429
  redistribute,
423
430
  getHandleRefCallback,
424
431
  toggleCollapsePanel,
425
432
  updateSizes,
426
- onCollapseChange
433
+ emitCollapseTransitions,
434
+ reset
427
435
  ]);
428
436
  (0, react.useEffect)(() => () => {
429
437
  documentControllerRef.current?.abort();
@@ -447,7 +455,8 @@ function useSplitter(options) {
447
455
  setSizes: updateSizes,
448
456
  collapse: collapsePanel,
449
457
  expand: expandPanel,
450
- toggleCollapse: toggleCollapsePanel
458
+ toggleCollapse: toggleCollapsePanel,
459
+ reset
451
460
  };
452
461
  }
453
462
  //#endregion