@mantine/hooks 9.1.0 → 9.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,7 +14,13 @@ function useFocusReturn({ opened, shouldReturnFocus = true }) {
14
14
  };
15
15
  document.addEventListener("keydown", clearFocusTimeout);
16
16
  if (opened) lastActiveElement.current = document.activeElement;
17
- else if (shouldReturnFocus) timeout = window.setTimeout(returnFocus, 10);
17
+ else if (shouldReturnFocus) {
18
+ const activeElementAtClose = document.activeElement;
19
+ timeout = window.setTimeout(() => {
20
+ const currentActiveElement = document.activeElement;
21
+ if (currentActiveElement === null || currentActiveElement === document.body || currentActiveElement === activeElementAtClose) returnFocus();
22
+ }, 10);
23
+ }
18
24
  return () => {
19
25
  window.clearTimeout(timeout);
20
26
  document.removeEventListener("keydown", clearFocusTimeout);
@@ -1 +1 @@
1
- {"version":3,"file":"use-focus-return.cjs","names":[],"sources":["../../src/use-focus-return/use-focus-return.ts"],"sourcesContent":["import { useRef } from 'react';\nimport { useDidUpdate } from '../use-did-update/use-did-update';\n\nexport interface UseFocusReturnInput {\n opened: boolean;\n shouldReturnFocus?: boolean;\n}\n\nexport type UseFocusReturnReturnValue = () => void;\n\nexport function useFocusReturn({\n opened,\n shouldReturnFocus = true,\n}: UseFocusReturnInput): UseFocusReturnReturnValue {\n const lastActiveElement = useRef<HTMLElement>(null);\n const returnFocus = () => {\n if (\n lastActiveElement.current &&\n 'focus' in lastActiveElement.current &&\n typeof lastActiveElement.current.focus === 'function'\n ) {\n lastActiveElement.current?.focus({ preventScroll: true });\n }\n };\n\n useDidUpdate(() => {\n let timeout = -1;\n\n const clearFocusTimeout = (event: KeyboardEvent) => {\n if (event.key === 'Tab') {\n window.clearTimeout(timeout);\n }\n };\n\n document.addEventListener('keydown', clearFocusTimeout);\n\n if (opened) {\n lastActiveElement.current = document.activeElement as HTMLElement;\n } else if (shouldReturnFocus) {\n timeout = window.setTimeout(returnFocus, 10);\n }\n\n return () => {\n window.clearTimeout(timeout);\n document.removeEventListener('keydown', clearFocusTimeout);\n };\n }, [opened, shouldReturnFocus]);\n\n return returnFocus;\n}\n\nexport namespace useFocusReturn {\n export type Input = UseFocusReturnInput;\n export type ReturnValue = UseFocusReturnReturnValue;\n}\n"],"mappings":";;;;AAUA,SAAgB,eAAe,EAC7B,QACA,oBAAoB,QAC6B;CACjD,MAAM,qBAAA,GAAA,MAAA,QAAwC,KAAK;CACnD,MAAM,oBAAoB;AACxB,MACE,kBAAkB,WAClB,WAAW,kBAAkB,WAC7B,OAAO,kBAAkB,QAAQ,UAAU,WAE3C,mBAAkB,SAAS,MAAM,EAAE,eAAe,MAAM,CAAC;;AAI7D,wBAAA,mBAAmB;EACjB,IAAI,UAAU;EAEd,MAAM,qBAAqB,UAAyB;AAClD,OAAI,MAAM,QAAQ,MAChB,QAAO,aAAa,QAAQ;;AAIhC,WAAS,iBAAiB,WAAW,kBAAkB;AAEvD,MAAI,OACF,mBAAkB,UAAU,SAAS;WAC5B,kBACT,WAAU,OAAO,WAAW,aAAa,GAAG;AAG9C,eAAa;AACX,UAAO,aAAa,QAAQ;AAC5B,YAAS,oBAAoB,WAAW,kBAAkB;;IAE3D,CAAC,QAAQ,kBAAkB,CAAC;AAE/B,QAAO"}
1
+ {"version":3,"file":"use-focus-return.cjs","names":[],"sources":["../../src/use-focus-return/use-focus-return.ts"],"sourcesContent":["import { useRef } from 'react';\nimport { useDidUpdate } from '../use-did-update/use-did-update';\n\nexport interface UseFocusReturnInput {\n opened: boolean;\n shouldReturnFocus?: boolean;\n}\n\nexport type UseFocusReturnReturnValue = () => void;\n\nexport function useFocusReturn({\n opened,\n shouldReturnFocus = true,\n}: UseFocusReturnInput): UseFocusReturnReturnValue {\n const lastActiveElement = useRef<HTMLElement>(null);\n const returnFocus = () => {\n if (\n lastActiveElement.current &&\n 'focus' in lastActiveElement.current &&\n typeof lastActiveElement.current.focus === 'function'\n ) {\n lastActiveElement.current?.focus({ preventScroll: true });\n }\n };\n\n useDidUpdate(() => {\n let timeout = -1;\n\n const clearFocusTimeout = (event: KeyboardEvent) => {\n if (event.key === 'Tab') {\n window.clearTimeout(timeout);\n }\n };\n\n document.addEventListener('keydown', clearFocusTimeout);\n\n if (opened) {\n lastActiveElement.current = document.activeElement as HTMLElement;\n } else if (shouldReturnFocus) {\n const activeElementAtClose = document.activeElement;\n timeout = window.setTimeout(() => {\n const currentActiveElement = document.activeElement;\n if (\n currentActiveElement === null ||\n currentActiveElement === document.body ||\n currentActiveElement === activeElementAtClose\n ) {\n returnFocus();\n }\n }, 10);\n }\n\n return () => {\n window.clearTimeout(timeout);\n document.removeEventListener('keydown', clearFocusTimeout);\n };\n }, [opened, shouldReturnFocus]);\n\n return returnFocus;\n}\n\nexport namespace useFocusReturn {\n export type Input = UseFocusReturnInput;\n export type ReturnValue = UseFocusReturnReturnValue;\n}\n"],"mappings":";;;;AAUA,SAAgB,eAAe,EAC7B,QACA,oBAAoB,QAC6B;CACjD,MAAM,qBAAA,GAAA,MAAA,QAAwC,KAAK;CACnD,MAAM,oBAAoB;AACxB,MACE,kBAAkB,WAClB,WAAW,kBAAkB,WAC7B,OAAO,kBAAkB,QAAQ,UAAU,WAE3C,mBAAkB,SAAS,MAAM,EAAE,eAAe,MAAM,CAAC;;AAI7D,wBAAA,mBAAmB;EACjB,IAAI,UAAU;EAEd,MAAM,qBAAqB,UAAyB;AAClD,OAAI,MAAM,QAAQ,MAChB,QAAO,aAAa,QAAQ;;AAIhC,WAAS,iBAAiB,WAAW,kBAAkB;AAEvD,MAAI,OACF,mBAAkB,UAAU,SAAS;WAC5B,mBAAmB;GAC5B,MAAM,uBAAuB,SAAS;AACtC,aAAU,OAAO,iBAAiB;IAChC,MAAM,uBAAuB,SAAS;AACtC,QACE,yBAAyB,QACzB,yBAAyB,SAAS,QAClC,yBAAyB,qBAEzB,cAAa;MAEd,GAAG;;AAGR,eAAa;AACX,UAAO,aAAa,QAAQ;AAC5B,YAAS,oBAAoB,WAAW,kBAAkB;;IAE3D,CAAC,QAAQ,kBAAkB,CAAC;AAE/B,QAAO"}
@@ -231,12 +231,14 @@ function useMask(options) {
231
231
  updateValue(reformatted, reformatted.length);
232
232
  }, [updateValue]);
233
233
  const clampCursorToProcessed = (0, react.useCallback)((input) => {
234
+ const start = input.selectionStart ?? 0;
235
+ if (start !== (input.selectionEnd ?? 0)) return;
234
236
  const opts = optionsRef.current;
235
237
  const { slots } = getResolvedOptions(opts, "");
236
238
  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);
239
+ const endPos = processed.length > 0 ? findNextEditablePosition(processed.length, slots, processed) : findNextTokenIndex(slots, 0);
240
+ const startPos = findNextTokenIndex(slots, 0);
241
+ if (start > endPos || start < startPos) input.setSelectionRange(endPos, endPos);
240
242
  }, []);
241
243
  const handleFocus = (0, react.useCallback)(() => {
242
244
  isFocusedRef.current = true;
@@ -260,13 +262,28 @@ function useMask(options) {
260
262
  if (!input || input !== document.activeElement) return;
261
263
  clampCursorToProcessed(input);
262
264
  }, [clampCursorToProcessed]);
265
+ const handleMouseDown = (0, react.useCallback)(() => {
266
+ const input = inputRef.current;
267
+ if (!input) return;
268
+ requestAnimationFrame(() => {
269
+ if (input !== document.activeElement) return;
270
+ const start = input.selectionStart ?? 0;
271
+ if (start !== (input.selectionEnd ?? 0)) return;
272
+ const opts = optionsRef.current;
273
+ const { slots } = getResolvedOptions(opts, "");
274
+ const processed = processedRef.current;
275
+ const endPos = processed.length > 0 ? findNextEditablePosition(processed.length, slots, processed) : findNextTokenIndex(slots, 0);
276
+ if (start > endPos) input.setSelectionRange(endPos, endPos);
277
+ });
278
+ }, []);
263
279
  const handleBlur = (0, react.useCallback)(() => {
264
280
  isFocusedRef.current = false;
265
281
  const opts = optionsRef.current;
266
282
  const input = inputRef.current;
267
283
  if (!input) return;
268
284
  const { slots, slotChar } = getResolvedOptions(opts, rawValue);
269
- const processed = processInput(input.value, slots, slotChar);
285
+ const expectedFocusDisplay = buildDisplayValue(processedRef.current, slots, slotChar, true);
286
+ const processed = input.value === expectedFocusDisplay ? processedRef.current : processInput(input.value, slots, slotChar);
270
287
  const complete = checkComplete(processed, slots);
271
288
  if (opts.autoClear && !complete && processed.length > 0) {
272
289
  input.value = "";
@@ -283,6 +300,15 @@ function useMask(options) {
283
300
  return;
284
301
  }
285
302
  if (!opts.alwaysShowMask && !complete) {
303
+ if (extractRaw(processed, slots).length === 0) {
304
+ input.value = "";
305
+ processedRef.current = "";
306
+ setMaskedValue("");
307
+ setRawValue("");
308
+ wasCompleteRef.current = false;
309
+ if (opts.onChangeRaw) opts.onChangeRaw("", "");
310
+ return;
311
+ }
286
312
  const display = buildDisplayValue(processed, slots, slotChar, false);
287
313
  input.value = display;
288
314
  setMaskedValue(display);
@@ -382,6 +408,7 @@ function useMask(options) {
382
408
  prevInput.removeEventListener("input", handleInput);
383
409
  prevInput.removeEventListener("focus", handleFocus);
384
410
  prevInput.removeEventListener("blur", handleBlur);
411
+ prevInput.removeEventListener("mousedown", handleMouseDown);
385
412
  prevInput.removeEventListener("mouseup", handleMouseUp);
386
413
  prevInput.removeEventListener("keydown", handleKeyDown);
387
414
  prevInput.removeEventListener("paste", handlePaste);
@@ -391,6 +418,7 @@ function useMask(options) {
391
418
  node.addEventListener("input", handleInput);
392
419
  node.addEventListener("focus", handleFocus);
393
420
  node.addEventListener("blur", handleBlur);
421
+ node.addEventListener("mousedown", handleMouseDown);
394
422
  node.addEventListener("mouseup", handleMouseUp);
395
423
  node.addEventListener("keydown", handleKeyDown);
396
424
  node.addEventListener("paste", handlePaste);
@@ -406,6 +434,7 @@ function useMask(options) {
406
434
  handleInput,
407
435
  handleFocus,
408
436
  handleBlur,
437
+ handleMouseDown,
409
438
  handleMouseUp,
410
439
  handleKeyDown,
411
440
  handlePaste,
@@ -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\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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"}
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 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 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 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 if (extractRaw(processed, slots).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 return;\n }\n\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('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 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 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":";;;AAEA,MAAM,iBAAyC;CAC7C,KAAK;CACL,GAAG;CACH,GAAG;CACH,KAAK;CACL,KAAK;CACN;AA8ED,SAAS,UACP,MACA,QACY;AACZ,KAAI,MAAM,QAAQ,KAAK,CACrB,QAAO,KAAK,KAAK,SAAS;AACxB,MAAI,gBAAgB,OAClB,QAAO;GAAE,MAAM;GAAS,MAAM;GAAK,SAAS;GAAM;AAEpD,SAAO;GAAE,MAAM;GAAW,MAAM;GAAM;GACtC;CAGJ,MAAM,QAAoB,EAAE;CAC5B,IAAI,WAAW;AAEf,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,OAAO,KAAK;AAElB,MAAI,SAAS,QAAQ,IAAI,IAAI,KAAK,QAAQ;AACxC;AACA,SAAM,KAAK;IAAE,MAAM;IAAW,MAAM,KAAK;IAAI,CAAC;AAC9C;;AAGF,MAAI,SAAS,KAAK;AAChB,cAAW;AACX;;AAGF,MAAI,OAAO,MACT,OAAM,KAAK;GAAE,MAAM;GAAS;GAAM,SAAS,OAAO;GAAO;GAAU,CAAC;MAEpE,OAAM,KAAK;GAAE,MAAM;GAAW;GAAM;GAAU,CAAC;;AAInD,QAAO;;AAGT,SAAS,YAAY,gBAA2C,OAAuB;AACrF,KAAI,mBAAmB,QAAQ,mBAAmB,MAAM,mBAAmB,KAAA,EACzE,QAAO;AAET,KAAI,eAAe,SAAS,EAC1B,QAAO,eAAe,UAAU;AAElC,QAAO;;AAGT,SAAS,eACP,KACA,OACA,iBACA,WACQ;CACR,IAAI,SAAS;CACb,IAAI,WAAW;CACf,IAAI,YAAY;AAEhB,MAAK,YAAY,GAAG,YAAY,MAAM,QAAQ,aAAa;EACzD,MAAM,OAAO,MAAM;AACnB,MAAI,KAAK,SAAS,UAChB,WAAU,KAAK;WACN,WAAW,IAAI,QAAQ;GAChC,MAAM,KAAK,YAAY,UAAU,IAAI,UAAU,GAAG,IAAI;AACtD,OAAI,KAAK,WAAW,KAAK,QAAQ,KAAK,GAAG,EAAE;AACzC,cAAU;AACV;UACK;AACL;AACA;;QAGF;;AAIJ,QAAO;;AAGT,SAAS,kBACP,OACA,OACA,gBACA,WACQ;AACR,KAAI,CAAC,UACH,QAAO;CAGT,IAAI,UAAU;AAEd,MAAK,IAAI,IAAI,MAAM,QAAQ,IAAI,MAAM,QAAQ,KAAK;EAChD,MAAM,OAAO,MAAM;AACnB,MAAI,KAAK,SAAS,UAChB,YAAW,KAAK;OACX;GACL,MAAM,KAAK,YAAY,gBAAgB,EAAE;AACzC,OAAI,CAAC,GACH;AAEF,cAAW;;;AAIf,QAAO;;AAGT,SAAS,WAAW,QAAgB,OAA2B;CAC7D,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,UAAU,IAAI,MAAM,QAAQ,IACrD,KAAI,MAAM,GAAG,SAAS,QACpB,QAAO,OAAO;AAGlB,QAAO;;AAGT,SAAS,cAAc,QAAgB,OAA4B;AACjE,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IAChC,KAAI,MAAM,GAAG,SAAS,WAAW,CAAC,MAAM,GAAG,UAAU;AACnD,MAAI,KAAK,OAAO,OACd,QAAO;AAET,MAAI,CAAC,MAAM,GAAG,QAAS,KAAK,OAAO,GAAG,CACpC,QAAO;;AAIb,QAAO;;AAGT,SAAS,mBAAmB,OAAmB,MAAsB;AACnE,MAAK,IAAI,IAAI,MAAM,IAAI,MAAM,QAAQ,IACnC,KAAI,MAAM,GAAG,SAAS,QACpB,QAAO;AAGX,QAAO,MAAM;;AAGf,SAAS,mBAAmB,OAAmB,MAAsB;AACnE,MAAK,IAAI,IAAI,MAAM,KAAK,GAAG,IACzB,KAAI,MAAM,GAAG,SAAS,QACpB,QAAO;AAGX,QAAO;;AAGT,SAAS,aACP,YACA,OACA,iBACQ;CACR,IAAI,SAAS;CACb,IAAI,aAAa;AAEjB,MACE,IAAI,YAAY,GAChB,YAAY,MAAM,UAAU,cAAc,WAAW,QACrD,aACA;EACA,MAAM,OAAO,MAAM;AAEnB,MAAI,KAAK,SAAS,WAAW;AAC3B,aAAU,KAAK;AACf,OAAI,aAAa,WAAW,UAAU,WAAW,gBAAgB,KAAK,KACpE;AAEF;;AAGF,MAAI,cAAc,WAAW,OAC3B;AAGF,SAAO,aAAa,WAAW,QAAQ;GACrC,MAAM,KAAK,WAAW;AACtB;AAEA,OAAI,KAAK,QAAS,KAAK,GAAG,EAAE;AAC1B,cAAU;AACV;;;AAIJ,MAAI,OAAO,UAAU,UACnB;;AAIJ,QAAO;;AAGT,SAAS,mBAAmB,SAAyB,UAAkB;CACrE,MAAM,SAAS;EAAE,GAAG;EAAgB,GAAG,QAAQ;EAAQ;CACvD,IAAI,OAAO,QAAQ;CACnB,IAAI,WAAsC,QAAQ,aAAa,KAAA,IAAY,MAAM,QAAQ;CACzF,IAAI,WAAW,QAAQ,YAAY;AAEnC,KAAI,QAAQ,QAAQ;EAClB,MAAM,YAAY,QAAQ,OAAO,SAAS;AAC1C,MAAI,WAAW;AACb,OAAI,UAAU,SAAS,KAAA,EACrB,QAAO,UAAU;AAEnB,OAAI,UAAU,WAAW,KAAA,EACvB,QAAO,OAAO,QAAQ,UAAU,OAAO;AAEzC,OAAI,UAAU,aAAa,KAAA,EACzB,YAAW,UAAU;AAEvB,OAAI,UAAU,aAAa,KAAA,EACzB,YAAW,UAAU;;;AAM3B,QAAO;EAAE,OADK,UAAU,MAAM,OAAO;EACrB;EAAU;EAAU;EAAQ,WAAW,QAAQ;EAAW;;AAG5E,SAAgB,WAAW,KAAa,SAAiC;CACvE,MAAM,EAAE,OAAO,UAAU,cAAc,mBAAmB,SAAS,IAAI;AACvE,QAAO,eAAe,KAAK,OAAO,UAAU,UAAU;;AAGxD,SAAgB,aAAa,QAAgB,SAAiC;CAC5E,MAAM,EAAE,UAAU,mBAAmB,SAAS,GAAG;AACjD,QAAO,WAAW,QAAQ,MAAM;;AAGlC,SAAgB,eAAe,QAAgB,SAAkC;CAC/E,MAAM,EAAE,UAAU,mBAAmB,SAAS,GAAG;AACjD,QAAO,cAAc,QAAQ,MAAM;;AAGrC,SAAgB,gBAAgB,MAA+B,SAAiC;CAC9F,MAAM,EAAE,UAAU,mBAAmB,SAAS,GAAG;CACjD,IAAI,UAAU;AAEd,MAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,SAAS,UAChB,YAAW,KAAK,KAAK,QAAQ,uBAAuB,OAAO;MACtD;EACL,MAAM,MAAM,KAAK,QAAS;AAC1B,MAAI,SAAS,eACX,YAAW,KAAK,WAAW,GAAG,IAAI,KAAK;MAEvC,YAAW,KAAK,WAAW,IAAI,IAAI,MAAM,IAAI,IAAI;;AAKvD,QAAO;;AAGT,SAAgB,QAAQ,SAA6C;CACnE,MAAM,cAAA,GAAA,MAAA,QAAoB,QAAQ;AAClC,YAAW,UAAU;CAErB,MAAM,YAAA,GAAA,MAAA,QAA2C,KAAK;CACtD,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,UAA2B,GAAG;CAClD,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,UAAwB,GAAG;CAC5C,MAAM,gBAAA,GAAA,MAAA,QAAsB,GAAG;CAC/B,MAAM,kBAAA,GAAA,MAAA,QAAwB,MAAM;CACpC,MAAM,gBAAA,GAAA,MAAA,QAAsB,MAAM;CAElC,MAAM,cAAA,GAAA,MAAA,mBAA+B;EACnC,MAAM,OAAO,WAAW;AACxB,SAAO,mBAAmB,MAAM,SAAS;IACxC,CAAC,SAAS,CAAC;CAEd,MAAM,eAAA,GAAA,MAAA,cACH,WAAmB,cAAuB;EACzC,MAAM,OAAO,WAAW;EACxB,MAAM,EAAE,UAAU,mBAChB,MACA,WAAW,WAAW,mBAAmB,MAAM,GAAG,CAAC,MAAM,CAC1D;EAGD,MAAM,EAAE,OAAO,eAAe,aAAa,mBAAmB,MAFlD,WAAW,WAAW,MAAM,CAEgC;EAExE,MAAM,cAAc,aAAa,WAAW,eAAe,SAAS;EACpE,MAAM,SAAS,WAAW,aAAa,cAAc;EAErD,MAAM,YAAY,KAAK,kBAAkB,aAAa;EACtD,MAAM,cAAc,KAAK,oBAAoB;EAG7C,MAAM,eAAe,kBAAkB,aAAa,eAAe,UAF3C,cAAc,eAAe,YAAY,SAAS,GAEmB;AAE7F,eAAa,UAAU;AACvB,iBAAe,aAAa;AAC5B,cAAY,OAAO;AAEnB,MAAI,SAAS,SAAS;AACpB,YAAS,QAAQ,QAAQ;AACzB,OAAI,cAAc,KAAA,KAAa,SAAS,kBAAkB,SAAS,SAAS;IAC1E,MAAM,MAAM,KAAK,IAAI,WAAW,YAAY,OAAO;AACnD,aAAS,QAAQ,kBAAkB,KAAK,IAAI;;;AAIhD,MAAI,KAAK,YACP,MAAK,YAAY,QAAQ,aAAa;EAGxC,MAAM,WAAW,cAAc,aAAa,cAAc;AAC1D,MAAI,YAAY,CAAC,eAAe,WAAW,KAAK,WAC9C,MAAK,WAAW,cAAc,OAAO;AAEvC,iBAAe,UAAU;AAEzB,SAAO;GAAE;GAAc;GAAQ;GAAa;GAAe;IAE7D,CAAC,WAAW,CACb;CAED,MAAM,eAAA,GAAA,MAAA,cACH,MAAa;EACZ,MAAM,QAAQ,EAAE;EAChB,MAAM,OAAO,WAAW;EAExB,MAAM,EAAE,OAAO,eAAe,UAAU,cAAc,mBAAmB,MAAM,GAAG;EAElF,MAAM,cAAc,eADR,WAAW,MAAM,OAAO,cAAc,EACV,eAAe,UAAU,UAAU;AAC3E,cAAY,aAAa,YAAY,OAAO;IAE9C,CAAC,YAAY,CACd;CAED,MAAM,0BAAA,GAAA,MAAA,cAAsC,UAA4B;EACtE,MAAM,QAAQ,MAAM,kBAAkB;AAEtC,MAAI,WADQ,MAAM,gBAAgB,GAEhC;EAGF,MAAM,OAAO,WAAW;EACxB,MAAM,EAAE,UAAU,mBAAmB,MAAM,GAAG;EAC9C,MAAM,YAAY,aAAa;EAC/B,MAAM,SACJ,UAAU,SAAS,IACf,yBAAyB,UAAU,QAAQ,OAAO,UAAU,GAC5D,mBAAmB,OAAO,EAAE;EAClC,MAAM,WAAW,mBAAmB,OAAO,EAAE;AAE7C,MAAI,QAAQ,UAAU,QAAQ,SAC5B,OAAM,kBAAkB,QAAQ,OAAO;IAExC,EAAE,CAAC;CAEN,MAAM,eAAA,GAAA,MAAA,mBAAgC;AACpC,eAAa,UAAU;EACvB,MAAM,OAAO,WAAW;EACxB,MAAM,QAAQ,SAAS;AAEvB,MAAI,CAAC,MACH;EAGF,MAAM,EAAE,OAAO,aAAa,mBAAmB,MAAM,GAAG;EACxD,MAAM,cAAc,KAAK,oBAAoB;EAC7C,MAAM,YAAY,aAAa;AAE/B,MAAI,eAAe,KAAK,gBAAgB;GACtC,MAAM,UAAU,kBAAkB,WAAW,OAAO,UAAU,KAAK;AACnE,SAAM,QAAQ;AACd,kBAAe,QAAQ;;AAGzB,8BAA4B;AAC1B,OAAI,UAAU,SAAS,cACrB,wBAAuB,MAAM;IAE/B;IACD,CAAC,uBAAuB,CAAC;CAE5B,MAAM,iBAAA,GAAA,MAAA,mBAAkC;EACtC,MAAM,QAAQ,SAAS;AACvB,MAAI,CAAC,SAAS,UAAU,SAAS,cAC/B;AAGF,yBAAuB,MAAM;IAC5B,CAAC,uBAAuB,CAAC;CAE5B,MAAM,mBAAA,GAAA,MAAA,mBAAoC;EACxC,MAAM,QAAQ,SAAS;AACvB,MAAI,CAAC,MACH;AAGF,8BAA4B;AAC1B,OAAI,UAAU,SAAS,cACrB;GAGF,MAAM,QAAQ,MAAM,kBAAkB;AAEtC,OAAI,WADQ,MAAM,gBAAgB,GAEhC;GAGF,MAAM,OAAO,WAAW;GACxB,MAAM,EAAE,UAAU,mBAAmB,MAAM,GAAG;GAC9C,MAAM,YAAY,aAAa;GAC/B,MAAM,SACJ,UAAU,SAAS,IACf,yBAAyB,UAAU,QAAQ,OAAO,UAAU,GAC5D,mBAAmB,OAAO,EAAE;AAElC,OAAI,QAAQ,OACV,OAAM,kBAAkB,QAAQ,OAAO;IAEzC;IACD,EAAE,CAAC;CAEN,MAAM,cAAA,GAAA,MAAA,mBAA+B;AACnC,eAAa,UAAU;EACvB,MAAM,OAAO,WAAW;EACxB,MAAM,QAAQ,SAAS;AAEvB,MAAI,CAAC,MACH;EAGF,MAAM,EAAE,OAAO,aAAa,mBAAmB,MAAM,SAAS;EAC9D,MAAM,uBAAuB,kBAAkB,aAAa,SAAS,OAAO,UAAU,KAAK;EAC3F,MAAM,YACJ,MAAM,UAAU,uBACZ,aAAa,UACb,aAAa,MAAM,OAAO,OAAO,SAAS;EAChD,MAAM,WAAW,cAAc,WAAW,MAAM;AAEhD,MAAI,KAAK,aAAa,CAAC,YAAY,UAAU,SAAS,GAAG;AACvD,SAAM,QAAQ;AACd,gBAAa,UAAU;AACvB,kBAAe,GAAG;AAClB,eAAY,GAAG;AACf,kBAAe,UAAU;AAEzB,OAAI,KAAK,YACP,MAAK,YAAY,IAAI,GAAG;AAG1B,OAAI,KAAK,gBAAgB;IACvB,MAAM,eAAe,kBAAkB,IAAI,OAAO,UAAU,KAAK;AACjE,UAAM,QAAQ;AACd,mBAAe,aAAa;;AAE9B;;AAGF,MAAI,CAAC,KAAK,kBAAkB,CAAC,UAAU;AACrC,OAAI,WAAW,WAAW,MAAM,CAAC,WAAW,GAAG;AAC7C,UAAM,QAAQ;AACd,iBAAa,UAAU;AACvB,mBAAe,GAAG;AAClB,gBAAY,GAAG;AACf,mBAAe,UAAU;AAEzB,QAAI,KAAK,YACP,MAAK,YAAY,IAAI,GAAG;AAE1B;;GAGF,MAAM,UAAU,kBAAkB,WAAW,OAAO,UAAU,MAAM;AACpE,SAAM,QAAQ;AACd,kBAAe,QAAQ;;IAExB,CAAC,SAAS,CAAC;CAEd,MAAM,iBAAA,GAAA,MAAA,cACH,MAAqB;EACpB,MAAM,QAAQ,EAAE;EAChB,MAAM,OAAO,WAAW;EAExB,MAAM,EAAE,OAAO,UAAU,cAAc,mBAAmB,MAAM,SAAS;EACzE,MAAM,QAAQ,MAAM,kBAAkB;EACtC,MAAM,MAAM,MAAM,gBAAgB;EAClC,MAAM,YAAY,aAAa;AAE/B,MAAI,EAAE,QAAQ,aAAa;AACzB,KAAE,gBAAgB;AAElB,OAAI,EAAE,WAAY,EAAE,WAAW,CAAC,EAAE,QAAS;IACzC,MAAM,eAAe,KAAK,IAAI,OAAO,UAAU,OAAO;AAGtD,gBADiB,eADA,WAAW,UAAU,MAAM,aAAa,EAAE,MAAM,MAAM,aAAa,CAAC,EAC3C,OAAO,UAAU,UAAU,EAC/C,EAAE;AACxB;;AAGF,OAAI,UAAU,KAAK;IACjB,MAAM,aAAa,KAAK,IAAI,KAAK,UAAU,OAAO;IAClD,MAAM,SAAS,UAAU,MAAM,GAAG,MAAM;IACxC,MAAM,WAAW,WAAW,UAAU,MAAM,WAAW,EAAE,MAAM,MAAM,WAAW,CAAC;AAOjF,gBANiB,eACf,WAAW,QAAQ,MAAM,GAAG,UAC5B,OACA,UACA,UACD,EACqB,MAAM;AAC5B;;AAGF,OAAI,UAAU,EACZ;GAGF,IAAI,YAAY,QAAQ;AACxB,UAAO,aAAa,KAAK,MAAM,cAAc,MAAM,WAAW,SAAS,UACrE;AAGF,OAAI,YAAY,EACd;AAMF,eADiB,eAFC,WAAW,UAAU,MAAM,GAAG,UAAU,EAAE,MAAM,MAAM,GAAG,UAAU,CAAC,GACrE,WAAW,UAAU,MAAM,YAAY,EAAE,EAAE,MAAM,MAAM,YAAY,EAAE,CAAC,EACjC,OAAO,UAAU,UAAU,EAC3D,UAAU;aACvB,EAAE,QAAQ,UAAU;AAC7B,KAAE,gBAAgB;AAElB,OAAI,UAAU,KAAK;IACjB,MAAM,aAAa,KAAK,IAAI,KAAK,UAAU,OAAO;IAClD,MAAM,SAAS,UAAU,MAAM,GAAG,MAAM;IACxC,MAAM,WAAW,WAAW,UAAU,MAAM,WAAW,EAAE,MAAM,MAAM,WAAW,CAAC;AAOjF,gBANiB,eACf,WAAW,QAAQ,MAAM,GAAG,UAC5B,OACA,UACA,UACD,EACqB,MAAM;AAC5B;;GAGF,IAAI,YAAY;AAChB,UACE,YAAY,MAAM,UAClB,MAAM,cACN,MAAM,WAAW,SAAS,UAE1B;AAGF,OAAI,aAAa,UAAU,OACzB;AAMF,eADiB,eAFC,WAAW,UAAU,MAAM,GAAG,MAAM,EAAE,MAAM,MAAM,GAAG,MAAM,CAAC,GAC7D,WAAW,UAAU,MAAM,YAAY,EAAE,EAAE,MAAM,MAAM,YAAY,EAAE,CAAC,EACjC,OAAO,UAAU,UAAU,EAC3D,MAAM;aACnB,EAAE,QAAQ,gBAAgB,CAAC,EAAE,UAAU;GAChD,MAAM,UAAU,yBAAyB,QAAQ,GAAG,OAAO,MAAM,MAAM;AACvE,OAAI,YAAY,QAAQ,GAAG;AACzB,MAAE,gBAAgB;AAClB,UAAM,kBAAkB,SAAS,QAAQ;;aAElC,EAAE,QAAQ,eAAe,CAAC,EAAE;OACjC,QAAQ,GAAG;IACb,MAAM,YAAY,mBAAmB,OAAO,QAAQ,EAAE;AACtD,QAAI,aAAa,KAAK,cAAc,QAAQ,GAAG;AAC7C,OAAE,gBAAgB;AAClB,WAAM,kBAAkB,YAAY,GAAG,YAAY,EAAE;;;aAGhD,EAAE,IAAI,WAAW,KAAK,CAAC,EAAE,WAAW,CAAC,EAAE,WAAW,CAAC,EAAE,QAAQ;AACtE,KAAE,gBAAgB;GAElB,IAAI,YAAY,KAAK,IAAI,OAAO,UAAU,OAAO;AACjD,UACE,YAAY,MAAM,UAClB,MAAM,cACN,MAAM,WAAW,SAAS,UAE1B;AAGF,OAAI,aAAa,MAAM,OACrB;GAGF,MAAM,OAAO,MAAM;GACnB,MAAM,KAAK,YAAY,UAAU,EAAE,IAAI,GAAG,EAAE;AAC5C,OAAI,CAAC,KAAK,QAAS,KAAK,GAAG,CACzB;GAGF,MAAM,YAAY,WAAW,UAAU,MAAM,GAAG,UAAU,EAAE,MAAM,MAAM,GAAG,UAAU,CAAC;GACtF,MAAM,WACJ,QAAQ,MACJ,WACE,UAAU,MAAM,KAAK,IAAI,KAAK,UAAU,OAAO,CAAC,EAChD,MAAM,MAAM,KAAK,IAAI,KAAK,UAAU,OAAO,CAAC,CAC7C,GACD,WAAW,UAAU,MAAM,UAAU,EAAE,MAAM,MAAM,UAAU,CAAC;GACpE,MAAM,WAAW,eAAe,YAAY,KAAK,UAAU,OAAO,UAAU,UAAU;AAEtF,eAAY,UADS,yBAAyB,YAAY,GAAG,OAAO,SAAS,CAC1C;;IAGvC,CAAC,UAAU,YAAY,CACxB;CAED,MAAM,eAAA,GAAA,MAAA,cACH,MAAsB;AACrB,IAAE,gBAAgB;EAClB,MAAM,QAAQ,EAAE;EAChB,MAAM,OAAO,WAAW;EAExB,MAAM,aAAa,EAAE,eAAe,QAAQ,OAAO,IAAI;EACvD,MAAM,QAAQ,MAAM,kBAAkB;EACtC,MAAM,MAAM,MAAM,gBAAgB;EAClC,MAAM,YAAY,aAAa;EAE/B,MAAM,EAAE,OAAO,UAAU,cAAc,mBAAmB,MAAM,GAAG;EACnE,MAAM,aAAa,KAAK,IAAI,KAAK,UAAU,OAAO;EAClD,MAAM,YAAY,WAAW,UAAU,MAAM,GAAG,MAAM,EAAE,MAAM,MAAM,GAAG,MAAM,CAAC;EAC9E,MAAM,WAAW,WAAW,UAAU,MAAM,WAAW,EAAE,MAAM,MAAM,WAAW,CAAC;EACjF,MAAM,WAAW,eACf,YAAY,aAAa,UACzB,OACA,UACA,UACD;EAED,MAAM,EAAE,gBAAgB,YAAY,SAAS;EAE7C,MAAM,cAAc,KAAK,KAAK,eAAe,UAAU,QAAQ,MAAM,OAAO;AAC5E,MAAI,UAAU,SAAS,cACrB,OAAM,kBAAkB,aAAa,YAAY;IAGrD,CAAC,YAAY,CACd;CAED,MAAM,qBAAA,GAAA,MAAA,cAAiC,UAA4B;AAGjE,MAFa,WAAW,QAEf,QACP,OAAM,aAAa,gBAAgB,OAAO;MAE1C,OAAM,gBAAgB,eAAe;IAEtC,EAAE,CAAC;CAEN,MAAM,eAAA,GAAA,MAAA,cACH,SAAkC;EACjC,MAAM,YAAY,SAAS;AAE3B,MAAI,WAAW;AACb,aAAU,oBAAoB,SAAS,YAAY;AACnD,aAAU,oBAAoB,SAAS,YAAY;AACnD,aAAU,oBAAoB,QAAQ,WAAW;AACjD,aAAU,oBAAoB,aAAa,gBAAgB;AAC3D,aAAU,oBAAoB,WAAW,cAAc;AACvD,aAAU,oBAAoB,WAAW,cAA+B;AACxE,aAAU,oBAAoB,SAAS,YAA6B;;AAGtE,WAAS,UAAU;AAEnB,MAAI,MAAM;AACR,QAAK,iBAAiB,SAAS,YAAY;AAC3C,QAAK,iBAAiB,SAAS,YAAY;AAC3C,QAAK,iBAAiB,QAAQ,WAAW;AACzC,QAAK,iBAAiB,aAAa,gBAAgB;AACnD,QAAK,iBAAiB,WAAW,cAAc;AAC/C,QAAK,iBAAiB,WAAW,cAA+B;AAChE,QAAK,iBAAiB,SAAS,YAA6B;AAE5D,qBAAkB,KAAK;AAEvB,OAAI,QAAQ,kBAAkB,CAAC,KAAK,OAAO;IACzC,MAAM,EAAE,OAAO,aAAa,mBAAmB,SAAS,GAAG;IAC3D,MAAM,UAAU,kBAAkB,IAAI,OAAO,UAAU,KAAK;AAC5D,SAAK,QAAQ;AACb,mBAAe,QAAQ;;;IAI7B;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,EAAA,GAAA,MAAA,iBAAgB;EACd,MAAM,QAAQ,SAAS;AACvB,MAAI,CAAC,MACH;AAGF,oBAAkB,MAAM;IACvB,CAAC,QAAQ,SAAS,kBAAkB,CAAC;AAgCxC,QAAO;EACL,KAAK;EACL,OAAO;EACP;EACA,mBAlCwB;GACxB,MAAM,EAAE,UAAU,YAAY;AAC9B,UAAO,cAAc,aAAa,SAAS,MAAM;MAC/C;EAgCF,QAAA,GAAA,MAAA,mBA9B8B;GAC9B,MAAM,OAAO,WAAW;GACxB,MAAM,QAAQ,SAAS;AAEvB,gBAAa,UAAU;AACvB,kBAAe,GAAG;AAClB,eAAY,GAAG;AACf,kBAAe,UAAU;AAEzB,OAAI,MACF,KAAI,KAAK,gBAAgB;IACvB,MAAM,EAAE,OAAO,aAAa,mBAAmB,MAAM,GAAG;IACxD,MAAM,UAAU,kBAAkB,IAAI,OAAO,UAAU,KAAK;AAC5D,UAAM,QAAQ;AACd,mBAAe,QAAQ;SAEvB,OAAM,QAAQ;AAIlB,OAAI,KAAK,YACP,MAAK,YAAY,IAAI,GAAG;KAEzB,EAAE,CAAC;EAQL;;AAGH,SAAS,yBAAyB,MAAc,OAAmB,OAAuB;CACxF,IAAI,MAAM;AACV,QAAO,MAAM,MAAM,UAAU,MAAM,MAAM,UAAU,MAAM,QAAQ,MAAM,KAAK,SAAS,UACnF;AAEF,QAAO"}
@@ -14,7 +14,13 @@ function useFocusReturn({ opened, shouldReturnFocus = true }) {
14
14
  };
15
15
  document.addEventListener("keydown", clearFocusTimeout);
16
16
  if (opened) lastActiveElement.current = document.activeElement;
17
- else if (shouldReturnFocus) timeout = window.setTimeout(returnFocus, 10);
17
+ else if (shouldReturnFocus) {
18
+ const activeElementAtClose = document.activeElement;
19
+ timeout = window.setTimeout(() => {
20
+ const currentActiveElement = document.activeElement;
21
+ if (currentActiveElement === null || currentActiveElement === document.body || currentActiveElement === activeElementAtClose) returnFocus();
22
+ }, 10);
23
+ }
18
24
  return () => {
19
25
  window.clearTimeout(timeout);
20
26
  document.removeEventListener("keydown", clearFocusTimeout);
@@ -1 +1 @@
1
- {"version":3,"file":"use-focus-return.mjs","names":[],"sources":["../../src/use-focus-return/use-focus-return.ts"],"sourcesContent":["import { useRef } from 'react';\nimport { useDidUpdate } from '../use-did-update/use-did-update';\n\nexport interface UseFocusReturnInput {\n opened: boolean;\n shouldReturnFocus?: boolean;\n}\n\nexport type UseFocusReturnReturnValue = () => void;\n\nexport function useFocusReturn({\n opened,\n shouldReturnFocus = true,\n}: UseFocusReturnInput): UseFocusReturnReturnValue {\n const lastActiveElement = useRef<HTMLElement>(null);\n const returnFocus = () => {\n if (\n lastActiveElement.current &&\n 'focus' in lastActiveElement.current &&\n typeof lastActiveElement.current.focus === 'function'\n ) {\n lastActiveElement.current?.focus({ preventScroll: true });\n }\n };\n\n useDidUpdate(() => {\n let timeout = -1;\n\n const clearFocusTimeout = (event: KeyboardEvent) => {\n if (event.key === 'Tab') {\n window.clearTimeout(timeout);\n }\n };\n\n document.addEventListener('keydown', clearFocusTimeout);\n\n if (opened) {\n lastActiveElement.current = document.activeElement as HTMLElement;\n } else if (shouldReturnFocus) {\n timeout = window.setTimeout(returnFocus, 10);\n }\n\n return () => {\n window.clearTimeout(timeout);\n document.removeEventListener('keydown', clearFocusTimeout);\n };\n }, [opened, shouldReturnFocus]);\n\n return returnFocus;\n}\n\nexport namespace useFocusReturn {\n export type Input = UseFocusReturnInput;\n export type ReturnValue = UseFocusReturnReturnValue;\n}\n"],"mappings":";;;;AAUA,SAAgB,eAAe,EAC7B,QACA,oBAAoB,QAC6B;CACjD,MAAM,oBAAoB,OAAoB,KAAK;CACnD,MAAM,oBAAoB;AACxB,MACE,kBAAkB,WAClB,WAAW,kBAAkB,WAC7B,OAAO,kBAAkB,QAAQ,UAAU,WAE3C,mBAAkB,SAAS,MAAM,EAAE,eAAe,MAAM,CAAC;;AAI7D,oBAAmB;EACjB,IAAI,UAAU;EAEd,MAAM,qBAAqB,UAAyB;AAClD,OAAI,MAAM,QAAQ,MAChB,QAAO,aAAa,QAAQ;;AAIhC,WAAS,iBAAiB,WAAW,kBAAkB;AAEvD,MAAI,OACF,mBAAkB,UAAU,SAAS;WAC5B,kBACT,WAAU,OAAO,WAAW,aAAa,GAAG;AAG9C,eAAa;AACX,UAAO,aAAa,QAAQ;AAC5B,YAAS,oBAAoB,WAAW,kBAAkB;;IAE3D,CAAC,QAAQ,kBAAkB,CAAC;AAE/B,QAAO"}
1
+ {"version":3,"file":"use-focus-return.mjs","names":[],"sources":["../../src/use-focus-return/use-focus-return.ts"],"sourcesContent":["import { useRef } from 'react';\nimport { useDidUpdate } from '../use-did-update/use-did-update';\n\nexport interface UseFocusReturnInput {\n opened: boolean;\n shouldReturnFocus?: boolean;\n}\n\nexport type UseFocusReturnReturnValue = () => void;\n\nexport function useFocusReturn({\n opened,\n shouldReturnFocus = true,\n}: UseFocusReturnInput): UseFocusReturnReturnValue {\n const lastActiveElement = useRef<HTMLElement>(null);\n const returnFocus = () => {\n if (\n lastActiveElement.current &&\n 'focus' in lastActiveElement.current &&\n typeof lastActiveElement.current.focus === 'function'\n ) {\n lastActiveElement.current?.focus({ preventScroll: true });\n }\n };\n\n useDidUpdate(() => {\n let timeout = -1;\n\n const clearFocusTimeout = (event: KeyboardEvent) => {\n if (event.key === 'Tab') {\n window.clearTimeout(timeout);\n }\n };\n\n document.addEventListener('keydown', clearFocusTimeout);\n\n if (opened) {\n lastActiveElement.current = document.activeElement as HTMLElement;\n } else if (shouldReturnFocus) {\n const activeElementAtClose = document.activeElement;\n timeout = window.setTimeout(() => {\n const currentActiveElement = document.activeElement;\n if (\n currentActiveElement === null ||\n currentActiveElement === document.body ||\n currentActiveElement === activeElementAtClose\n ) {\n returnFocus();\n }\n }, 10);\n }\n\n return () => {\n window.clearTimeout(timeout);\n document.removeEventListener('keydown', clearFocusTimeout);\n };\n }, [opened, shouldReturnFocus]);\n\n return returnFocus;\n}\n\nexport namespace useFocusReturn {\n export type Input = UseFocusReturnInput;\n export type ReturnValue = UseFocusReturnReturnValue;\n}\n"],"mappings":";;;;AAUA,SAAgB,eAAe,EAC7B,QACA,oBAAoB,QAC6B;CACjD,MAAM,oBAAoB,OAAoB,KAAK;CACnD,MAAM,oBAAoB;AACxB,MACE,kBAAkB,WAClB,WAAW,kBAAkB,WAC7B,OAAO,kBAAkB,QAAQ,UAAU,WAE3C,mBAAkB,SAAS,MAAM,EAAE,eAAe,MAAM,CAAC;;AAI7D,oBAAmB;EACjB,IAAI,UAAU;EAEd,MAAM,qBAAqB,UAAyB;AAClD,OAAI,MAAM,QAAQ,MAChB,QAAO,aAAa,QAAQ;;AAIhC,WAAS,iBAAiB,WAAW,kBAAkB;AAEvD,MAAI,OACF,mBAAkB,UAAU,SAAS;WAC5B,mBAAmB;GAC5B,MAAM,uBAAuB,SAAS;AACtC,aAAU,OAAO,iBAAiB;IAChC,MAAM,uBAAuB,SAAS;AACtC,QACE,yBAAyB,QACzB,yBAAyB,SAAS,QAClC,yBAAyB,qBAEzB,cAAa;MAEd,GAAG;;AAGR,eAAa;AACX,UAAO,aAAa,QAAQ;AAC5B,YAAS,oBAAoB,WAAW,kBAAkB;;IAE3D,CAAC,QAAQ,kBAAkB,CAAC;AAE/B,QAAO"}
@@ -231,12 +231,14 @@ function useMask(options) {
231
231
  updateValue(reformatted, reformatted.length);
232
232
  }, [updateValue]);
233
233
  const clampCursorToProcessed = useCallback((input) => {
234
+ const start = input.selectionStart ?? 0;
235
+ if (start !== (input.selectionEnd ?? 0)) return;
234
236
  const opts = optionsRef.current;
235
237
  const { slots } = getResolvedOptions(opts, "");
236
238
  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);
239
+ const endPos = processed.length > 0 ? findNextEditablePosition(processed.length, slots, processed) : findNextTokenIndex(slots, 0);
240
+ const startPos = findNextTokenIndex(slots, 0);
241
+ if (start > endPos || start < startPos) input.setSelectionRange(endPos, endPos);
240
242
  }, []);
241
243
  const handleFocus = useCallback(() => {
242
244
  isFocusedRef.current = true;
@@ -260,13 +262,28 @@ function useMask(options) {
260
262
  if (!input || input !== document.activeElement) return;
261
263
  clampCursorToProcessed(input);
262
264
  }, [clampCursorToProcessed]);
265
+ const handleMouseDown = useCallback(() => {
266
+ const input = inputRef.current;
267
+ if (!input) return;
268
+ requestAnimationFrame(() => {
269
+ if (input !== document.activeElement) return;
270
+ const start = input.selectionStart ?? 0;
271
+ if (start !== (input.selectionEnd ?? 0)) return;
272
+ const opts = optionsRef.current;
273
+ const { slots } = getResolvedOptions(opts, "");
274
+ const processed = processedRef.current;
275
+ const endPos = processed.length > 0 ? findNextEditablePosition(processed.length, slots, processed) : findNextTokenIndex(slots, 0);
276
+ if (start > endPos) input.setSelectionRange(endPos, endPos);
277
+ });
278
+ }, []);
263
279
  const handleBlur = useCallback(() => {
264
280
  isFocusedRef.current = false;
265
281
  const opts = optionsRef.current;
266
282
  const input = inputRef.current;
267
283
  if (!input) return;
268
284
  const { slots, slotChar } = getResolvedOptions(opts, rawValue);
269
- const processed = processInput(input.value, slots, slotChar);
285
+ const expectedFocusDisplay = buildDisplayValue(processedRef.current, slots, slotChar, true);
286
+ const processed = input.value === expectedFocusDisplay ? processedRef.current : processInput(input.value, slots, slotChar);
270
287
  const complete = checkComplete(processed, slots);
271
288
  if (opts.autoClear && !complete && processed.length > 0) {
272
289
  input.value = "";
@@ -283,6 +300,15 @@ function useMask(options) {
283
300
  return;
284
301
  }
285
302
  if (!opts.alwaysShowMask && !complete) {
303
+ if (extractRaw(processed, slots).length === 0) {
304
+ input.value = "";
305
+ processedRef.current = "";
306
+ setMaskedValue("");
307
+ setRawValue("");
308
+ wasCompleteRef.current = false;
309
+ if (opts.onChangeRaw) opts.onChangeRaw("", "");
310
+ return;
311
+ }
286
312
  const display = buildDisplayValue(processed, slots, slotChar, false);
287
313
  input.value = display;
288
314
  setMaskedValue(display);
@@ -382,6 +408,7 @@ function useMask(options) {
382
408
  prevInput.removeEventListener("input", handleInput);
383
409
  prevInput.removeEventListener("focus", handleFocus);
384
410
  prevInput.removeEventListener("blur", handleBlur);
411
+ prevInput.removeEventListener("mousedown", handleMouseDown);
385
412
  prevInput.removeEventListener("mouseup", handleMouseUp);
386
413
  prevInput.removeEventListener("keydown", handleKeyDown);
387
414
  prevInput.removeEventListener("paste", handlePaste);
@@ -391,6 +418,7 @@ function useMask(options) {
391
418
  node.addEventListener("input", handleInput);
392
419
  node.addEventListener("focus", handleFocus);
393
420
  node.addEventListener("blur", handleBlur);
421
+ node.addEventListener("mousedown", handleMouseDown);
394
422
  node.addEventListener("mouseup", handleMouseUp);
395
423
  node.addEventListener("keydown", handleKeyDown);
396
424
  node.addEventListener("paste", handlePaste);
@@ -406,6 +434,7 @@ function useMask(options) {
406
434
  handleInput,
407
435
  handleFocus,
408
436
  handleBlur,
437
+ handleMouseDown,
409
438
  handleMouseUp,
410
439
  handleKeyDown,
411
440
  handlePaste,
@@ -1 +1 @@
1
- {"version":3,"file":"use-mask.mjs","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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"}
1
+ {"version":3,"file":"use-mask.mjs","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 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 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 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 if (extractRaw(processed, slots).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 return;\n }\n\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('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 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 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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mantine/hooks",
3
- "version": "9.1.0",
3
+ "version": "9.1.1",
4
4
  "description": "A collection of 50+ hooks for state and UI management",
5
5
  "homepage": "https://mantine.dev",
6
6
  "license": "MIT",