use-mask-input 3.10.0 → 3.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/dist/antd.cjs +1 -65
  3. package/dist/antd.cjs.map +1 -1
  4. package/dist/antd.d.cts +12 -10
  5. package/dist/{antd.d.ts → antd.d.mts} +12 -10
  6. package/dist/antd.mjs +2 -0
  7. package/dist/antd.mjs.map +1 -0
  8. package/dist/index-BmKzoe0X.d.cts +836 -0
  9. package/dist/index-BmKzoe0X.d.mts +836 -0
  10. package/dist/index.cjs +1 -173
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +18 -15
  13. package/dist/{index.d.ts → index.d.mts} +18 -15
  14. package/dist/index.mjs +2 -0
  15. package/dist/index.mjs.map +1 -0
  16. package/dist/withMask-VWeBqi_u.cjs +2 -0
  17. package/dist/withMask-VWeBqi_u.cjs.map +1 -0
  18. package/dist/withMask-jrErtLYS.mjs +2 -0
  19. package/dist/withMask-jrErtLYS.mjs.map +1 -0
  20. package/package.json +42 -22
  21. package/src/api/withMask.ts +1 -1
  22. package/src/core/inputmask.ts +10 -0
  23. package/src/core/maskEngine.ts +2 -2
  24. package/src/utils/maskHelpers.ts +5 -3
  25. package/dist/antd.js +0 -63
  26. package/dist/antd.js.map +0 -1
  27. package/dist/chunk-DTC7JTZP.cjs +0 -3925
  28. package/dist/chunk-DTC7JTZP.cjs.map +0 -1
  29. package/dist/chunk-TVCNC3TP.js +0 -3915
  30. package/dist/chunk-TVCNC3TP.js.map +0 -1
  31. package/dist/index-D8KkaDbQ.d.cts +0 -596
  32. package/dist/index-D8KkaDbQ.d.ts +0 -596
  33. package/dist/index.js +0 -165
  34. package/dist/index.js.map +0 -1
  35. package/src/antd/useHookFormMaskAntd.spec.ts +0 -181
  36. package/src/antd/useMaskInputAntd-server.spec.tsx +0 -37
  37. package/src/antd/useMaskInputAntd.spec.tsx +0 -131
  38. package/src/api/useHookFormMask.spec.ts +0 -259
  39. package/src/api/useMaskInput-server.spec.tsx +0 -30
  40. package/src/api/useMaskInput.spec.tsx +0 -238
  41. package/src/api/withHookFormMask.spec.ts +0 -179
  42. package/src/api/withMask.spec.ts +0 -137
  43. package/src/api/withTanStackFormMask.spec.ts +0 -76
  44. package/src/core/elementResolver.spec.ts +0 -175
  45. package/src/core/maskConfig.spec.ts +0 -208
  46. package/src/core/maskEngine.spec.ts +0 -114
  47. package/src/utils/flow.spec.ts +0 -57
  48. package/src/utils/isServer.spec.ts +0 -15
  49. package/src/utils/moduleInterop.spec.ts +0 -37
package/dist/index.js DELETED
@@ -1,165 +0,0 @@
1
- import { getUnmaskedValue, resolveInputRef, withMask, isServer_default, setUnmaskedValue, makeMaskCacheKey, flow, setPrevRef, applyMaskToElement } from './chunk-TVCNC3TP.js';
2
- export { withMask } from './chunk-TVCNC3TP.js';
3
- import { useRef, useCallback, useEffect, useLayoutEffect, useMemo } from 'react';
4
-
5
- function useMaskInput(props) {
6
- const { mask, register, options } = props;
7
- const ref = useRef(null);
8
- const maskRef = useRef(mask);
9
- const optionsRef = useRef(options);
10
- const unmaskedValue = useCallback(() => getUnmaskedValue(ref.current), []);
11
- const refCallback = useCallback((input) => {
12
- if (!input) {
13
- ref.current = null;
14
- return;
15
- }
16
- ref.current = resolveInputRef(input);
17
- withMask(maskRef.current, optionsRef.current)(ref.current);
18
- }, []);
19
- useEffect(() => {
20
- if (isServer_default || !ref.current || !register) return;
21
- register(ref.current);
22
- }, [register]);
23
- if (isServer_default) {
24
- const noop = (() => {
25
- });
26
- return setUnmaskedValue(noop, () => "");
27
- }
28
- return setUnmaskedValue(refCallback, unmaskedValue);
29
- }
30
- function useHookFormMask(registerFn) {
31
- const entryCacheRef = useRef(/* @__PURE__ */ new Map());
32
- useLayoutEffect(() => {
33
- entryCacheRef.current.forEach((entry) => {
34
- const currentEntry = entry;
35
- if (!currentEntry.element || !currentEntry.latestRHFRef) return;
36
- if (currentEntry.latestRHFRef !== currentEntry.syncedRHFRef) {
37
- currentEntry.latestRHFRef(currentEntry.element);
38
- currentEntry.syncedRHFRef = currentEntry.latestRHFRef;
39
- }
40
- });
41
- });
42
- return useMemo(() => {
43
- entryCacheRef.current = /* @__PURE__ */ new Map();
44
- return (fieldName, mask, options) => {
45
- if (!registerFn) throw new Error("registerFn is required");
46
- const registerReturn = registerFn(fieldName, options);
47
- const { ref } = registerReturn;
48
- const cacheKey = makeMaskCacheKey(fieldName, mask);
49
- let entry = entryCacheRef.current.get(cacheKey);
50
- if (!entry) {
51
- const nextEntry = {
52
- element: null,
53
- latestRHFRef: ref,
54
- syncedRHFRef: void 0,
55
- stableRef: null
56
- };
57
- const applyMaskToRef = (_ref) => {
58
- nextEntry.element = _ref;
59
- if (_ref) applyMaskToElement(_ref, mask, options);
60
- return _ref;
61
- };
62
- nextEntry.stableRef = nextEntry.latestRHFRef ? flow(applyMaskToRef, (_ref) => nextEntry.latestRHFRef?.(_ref)) : applyMaskToRef;
63
- entry = nextEntry;
64
- entryCacheRef.current.set(cacheKey, nextEntry);
65
- } else {
66
- entry.latestRHFRef = ref;
67
- }
68
- const result = {
69
- ...registerReturn,
70
- ref: entry.stableRef
71
- };
72
- setUnmaskedValue(result, () => getUnmaskedValue(entry?.element ?? null));
73
- setPrevRef(result, ref);
74
- return result;
75
- };
76
- }, [registerFn]);
77
- }
78
-
79
- // src/api/withTanStackFormMask.ts
80
- var refCache = /* @__PURE__ */ new WeakMap();
81
- function withTanStackFormMask(inputProps, mask, options) {
82
- const { ref } = inputProps;
83
- if (!ref) {
84
- let currentElement = null;
85
- const result2 = {
86
- ...inputProps,
87
- ref: ((input) => {
88
- currentElement = input;
89
- if (input) applyMaskToElement(input, mask, options);
90
- })
91
- };
92
- setUnmaskedValue(result2, () => getUnmaskedValue(currentElement));
93
- setPrevRef(result2, ref);
94
- return result2;
95
- }
96
- if (!refCache.has(ref)) {
97
- refCache.set(ref, /* @__PURE__ */ new Map());
98
- }
99
- const maskCache = refCache.get(ref);
100
- const cacheKey = makeMaskCacheKey(inputProps.name ?? "", mask);
101
- if (!maskCache?.has(cacheKey)) {
102
- const maskedRef2 = ((input) => {
103
- maskedRef2.currentElement = input;
104
- if (input) applyMaskToElement(input, mask, options);
105
- ref(input);
106
- });
107
- maskCache?.set(cacheKey, maskedRef2);
108
- }
109
- const maskedRef = maskCache?.get(cacheKey);
110
- const result = {
111
- ...inputProps,
112
- ref: maskedRef
113
- };
114
- setUnmaskedValue(result, () => getUnmaskedValue(maskedRef?.currentElement ?? null));
115
- setPrevRef(result, ref);
116
- return result;
117
- }
118
-
119
- // src/api/useTanStackFormMask.ts
120
- function useTanStackFormMask() {
121
- return useMemo(
122
- () => (mask, inputProps, options) => withTanStackFormMask(inputProps, mask, options),
123
- []
124
- );
125
- }
126
-
127
- // src/api/withHookFormMask.ts
128
- var refCache2 = /* @__PURE__ */ new WeakMap();
129
- function withHookFormMask(register, mask, options) {
130
- const { ref } = register;
131
- if (!ref) {
132
- const result2 = {
133
- ...register,
134
- ref: null
135
- };
136
- setUnmaskedValue(result2, () => "");
137
- setPrevRef(result2, ref);
138
- return result2;
139
- }
140
- if (!refCache2.has(ref)) {
141
- refCache2.set(ref, /* @__PURE__ */ new Map());
142
- }
143
- const maskCache = refCache2.get(ref);
144
- const cacheKey = makeMaskCacheKey(register.name, mask);
145
- if (!maskCache?.has(cacheKey)) {
146
- const maskedRef2 = ((input) => {
147
- maskedRef2.currentElement = input;
148
- if (input) applyMaskToElement(input, mask, options);
149
- return ref(input);
150
- });
151
- maskCache?.set(cacheKey, maskedRef2);
152
- }
153
- const maskedRef = maskCache?.get(cacheKey);
154
- const result = {
155
- ...register,
156
- ref: maskedRef
157
- };
158
- setUnmaskedValue(result, () => getUnmaskedValue(maskedRef?.currentElement ?? null));
159
- setPrevRef(result, ref);
160
- return result;
161
- }
162
-
163
- export { useHookFormMask, useMaskInput, useTanStackFormMask, withHookFormMask, withTanStackFormMask };
164
- //# sourceMappingURL=index.js.map
165
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/useMaskInput.ts","../src/api/useHookFormMask.ts","../src/api/withTanStackFormMask.ts","../src/api/useTanStackFormMask.ts","../src/api/withHookFormMask.ts"],"names":["useRef","result","maskedRef","useMemo","refCache"],"mappings":"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","file":"index.js","sourcesContent":["import {\n useCallback, useEffect, useRef,\n} from 'react';\n\nimport { resolveInputRef } from '../core';\nimport withMask from './withMask';\nimport isServer from '../utils/isServer';\nimport { getUnmaskedValue, setUnmaskedValue } from '../utils';\n\nimport type {\n Input, Mask, Options, UseMaskInputReturn,\n} from '../types';\n\ninterface UseMaskInputOptions {\n mask: Mask;\n register?: (element: HTMLElement) => void;\n options?: Options;\n}\n\n/**\n * React hook for applying input masks to form elements.\n * Works with Ant Design and other wrapped components too.\n *\n * @param props - Configuration object\n * @param props.mask - The mask pattern to apply\n * @param props.register - Optional callback that receives the element\n * @param props.options - Optional mask configuration options\n * @returns A ref callback function to attach to the input element\n */\nexport default function useMaskInput(props: UseMaskInputOptions): UseMaskInputReturn {\n const { mask, register, options } = props;\n const ref = useRef<HTMLInputElement | null>(null);\n const maskRef = useRef(mask);\n const optionsRef = useRef(options);\n const unmaskedValue = useCallback(() => getUnmaskedValue(ref.current), []);\n\n const refCallback = useCallback((input: Input | null): void => {\n if (!input) {\n ref.current = null;\n return;\n }\n\n ref.current = resolveInputRef(input);\n withMask(maskRef.current, optionsRef.current)(ref.current);\n }, []);\n\n useEffect(() => {\n if (isServer || !ref.current || !register) return;\n register(ref.current);\n }, [register]);\n\n if (isServer) {\n const noop = (() => {\n // server doesn't have dom, so just do nothing\n }) as unknown as UseMaskInputReturn;\n\n return setUnmaskedValue(noop, () => '');\n }\n\n return setUnmaskedValue(refCallback, unmaskedValue);\n}\n","import { useLayoutEffect, useMemo, useRef } from 'react';\n\nimport { applyMaskToElement } from '../core';\nimport {\n flow, getUnmaskedValue, makeMaskCacheKey, setPrevRef, setUnmaskedValue,\n} from '../utils';\n\nimport type { RefCallback } from 'react';\nimport type {\n FieldValues, Path,\n RegisterOptions,\n UseFormRegister,\n} from 'react-hook-form';\n\nimport type { Mask, Options, UseHookFormMaskReturn } from '../types';\n\ninterface CacheEntry {\n stableRef: RefCallback<HTMLElement | null>;\n element: HTMLElement | null;\n latestRHFRef?: RefCallback<HTMLElement | null>;\n syncedRHFRef?: RefCallback<HTMLElement | null>;\n}\n\n/**\n * Creates a masked version of React Hook Form's register function.\n * Takes react-hook-form's register and adds automatic masking. Like an upgrade.\n *\n * @template T - The form data type\n * @template D - The register options type\n * @param registerFn - The register function from useForm hook\n * @returns A function that registers a field with mask support\n */\nexport default function useHookFormMask<\n T extends FieldValues, D extends RegisterOptions,\n>(registerFn: UseFormRegister<T>): ((fieldName: Path<T>, mask: Mask, options?: (\n D & Options) | Options | D) => UseHookFormMaskReturn<T>) {\n const entryCacheRef = useRef(new Map<string, CacheEntry>());\n\n useLayoutEffect(() => {\n entryCacheRef.current.forEach((entry) => {\n const currentEntry = entry;\n if (!currentEntry.element || !currentEntry.latestRHFRef) return;\n\n // After reset(), RHF gives us a new ref callback. React won't call it\n // because our outward ref identity stays stable, so we replay it here.\n if (currentEntry.latestRHFRef !== currentEntry.syncedRHFRef) {\n currentEntry.latestRHFRef(currentEntry.element);\n currentEntry.syncedRHFRef = currentEntry.latestRHFRef;\n }\n });\n });\n\n return useMemo(() => {\n // registerFn identity changed, so drop cached refs bound to the previous\n // register lifecycle.\n entryCacheRef.current = new Map<string, CacheEntry>();\n\n return (fieldName: Path<T>, mask: Mask, options?: (\n D & Options) | Options | D): UseHookFormMaskReturn<T> => {\n if (!registerFn) throw new Error('registerFn is required');\n\n const registerReturn = registerFn(fieldName, options as Options);\n const { ref } = registerReturn as UseHookFormMaskReturn<T>;\n\n const cacheKey = makeMaskCacheKey(fieldName, mask);\n\n let entry = entryCacheRef.current.get(cacheKey);\n if (!entry) {\n const nextEntry: CacheEntry = {\n element: null,\n latestRHFRef: ref,\n syncedRHFRef: undefined,\n stableRef: null as unknown as RefCallback<HTMLElement | null>,\n };\n\n const applyMaskToRef = (_ref: HTMLElement | null) => {\n nextEntry.element = _ref;\n if (_ref) applyMaskToElement(_ref, mask, options as Options);\n return _ref;\n };\n\n nextEntry.stableRef = (\n nextEntry.latestRHFRef\n ? flow(applyMaskToRef, (_ref: HTMLElement | null) => nextEntry.latestRHFRef?.(_ref))\n : applyMaskToRef\n ) as RefCallback<HTMLElement | null>;\n\n entry = nextEntry;\n entryCacheRef.current.set(cacheKey, nextEntry);\n } else {\n entry.latestRHFRef = ref;\n }\n\n const result = {\n ...registerReturn,\n ref: entry.stableRef,\n } as UseHookFormMaskReturn<T>;\n setUnmaskedValue(result, () => getUnmaskedValue(entry?.element ?? null));\n\n setPrevRef(result, ref);\n\n return result;\n };\n }, [registerFn]);\n}\n","import { applyMaskToElement } from '../core';\nimport {\n getUnmaskedValue, makeMaskCacheKey, setPrevRef, setUnmaskedValue,\n} from '../utils';\n\nimport type { RefCallback } from 'react';\n\nimport type {\n Mask, Options, TanStackFormInputProps, UseTanStackFormMaskReturn,\n} from '../types';\n\ntype MaskedRefCallback = RefCallback<HTMLElement | null> & {\n currentElement?: HTMLElement | null;\n};\n\nconst refCache = new WeakMap<\n RefCallback<HTMLElement | null>,\n Map<string, RefCallback<HTMLElement | null>>\n>();\n\n/**\n * Enhances TanStack Form-compatible input props with mask support.\n * Works with objects returned by field.getInputProps().\n */\nexport default function withTanStackFormMask<T extends TanStackFormInputProps>(\n inputProps: T,\n mask: Mask,\n options?: Options,\n): UseTanStackFormMaskReturn<T> {\n const { ref } = inputProps;\n\n if (!ref) {\n let currentElement: HTMLElement | null = null;\n const result = {\n ...inputProps,\n ref: ((input: HTMLElement | null) => {\n currentElement = input;\n if (input) applyMaskToElement(input, mask, options);\n }) as RefCallback<HTMLElement | null>,\n } as unknown as UseTanStackFormMaskReturn<T>;\n setUnmaskedValue(result, () => getUnmaskedValue(currentElement));\n\n setPrevRef(result, ref);\n return result;\n }\n\n if (!refCache.has(ref)) {\n refCache.set(ref, new Map());\n }\n\n const maskCache = refCache.get(ref);\n const cacheKey = makeMaskCacheKey(inputProps.name ?? '', mask);\n\n if (!maskCache?.has(cacheKey)) {\n const maskedRef = ((input: HTMLElement | null) => {\n maskedRef.currentElement = input;\n if (input) applyMaskToElement(input, mask, options);\n ref(input);\n }) as MaskedRefCallback;\n\n maskCache?.set(cacheKey, maskedRef);\n }\n\n const maskedRef = maskCache?.get(cacheKey) as MaskedRefCallback | undefined;\n const result = {\n ...inputProps,\n ref: maskedRef,\n } as unknown as UseTanStackFormMaskReturn<T>;\n setUnmaskedValue(result, () => getUnmaskedValue(maskedRef?.currentElement ?? null));\n\n setPrevRef(result, ref);\n return result;\n}\n","import { useMemo } from 'react';\n\nimport withTanStackFormMask from './withTanStackFormMask';\n\nimport type { Mask, Options, TanStackFormInputProps, UseTanStackFormMaskReturn } from '../types';\n\n/**\n * Creates a helper to mask TanStack Form-compatible input props.\n * Designed for objects returned by field.getInputProps().\n */\nexport default function useTanStackFormMask(): <T extends TanStackFormInputProps>(\n mask: Mask,\n inputProps: T,\n options?: Options,\n) => UseTanStackFormMaskReturn<T> {\n return useMemo(\n () => <T extends TanStackFormInputProps>(\n mask: Mask,\n inputProps: T,\n options?: Options,\n ): UseTanStackFormMaskReturn<T> => withTanStackFormMask(inputProps, mask, options),\n [],\n );\n}\n","import { applyMaskToElement } from '../core';\nimport {\n getUnmaskedValue, makeMaskCacheKey, setPrevRef, setUnmaskedValue,\n} from '../utils';\n\nimport type { RefCallback } from 'react';\nimport type { FieldValues } from 'react-hook-form';\n\nimport type {\n Mask, Options, UseFormRegisterReturn, UseHookFormMaskReturn,\n} from '../types';\n\ntype MaskedRefCallback = RefCallback<HTMLElement | null> & {\n currentElement?: HTMLElement | null;\n};\n\nconst refCache = new WeakMap<\n RefCallback<HTMLElement | null>,\n Map<string, RefCallback<HTMLElement | null>>\n>();\n\n/**\n * Enhances a React Hook Form register return object with mask support.\n * Takes an already registered field and adds mask to it.\n * Useful when you registered the field before.\n *\n * @param register - The register return object from React Hook Form\n * @param mask - The mask pattern to apply\n * @param options - Optional mask configuration options\n * @returns A new register return object with mask applied\n */\nexport default function withHookFormMask(\n register: UseFormRegisterReturn,\n mask: Mask,\n options?: Options,\n): UseHookFormMaskReturn<FieldValues> {\n const { ref } = register as UseHookFormMaskReturn<FieldValues>;\n\n // null ref — nothing to cache, return as-is.\n if (!ref) {\n const result = {\n ...register,\n ref: null as unknown as RefCallback<HTMLElement | null>,\n } as UseHookFormMaskReturn<FieldValues>;\n setUnmaskedValue(result, () => '');\n setPrevRef(result, ref);\n return result;\n }\n\n if (!refCache.has(ref)) {\n refCache.set(ref, new Map());\n }\n const maskCache = refCache.get(ref);\n const cacheKey = makeMaskCacheKey(register.name, mask);\n\n if (!maskCache?.has(cacheKey)) {\n const maskedRef = ((input: HTMLElement | null) => {\n maskedRef.currentElement = input;\n if (input) applyMaskToElement(input, mask, options);\n return ref(input);\n }) as MaskedRefCallback;\n\n maskCache?.set(cacheKey, maskedRef);\n }\n\n const maskedRef = maskCache?.get(cacheKey) as MaskedRefCallback | undefined;\n const result = {\n ...register,\n ref: maskedRef,\n } as UseHookFormMaskReturn<FieldValues>;\n setUnmaskedValue(result, () => getUnmaskedValue(maskedRef?.currentElement ?? null));\n\n setPrevRef(result, ref);\n\n return result;\n}\n"]}
@@ -1,181 +0,0 @@
1
- import { renderHook } from '@testing-library/react';
2
- import {
3
- beforeEach,
4
- describe,
5
- expect,
6
- it,
7
- vi,
8
- } from 'vitest';
9
-
10
- import { applyMaskToElement, resolveInputRef } from '../core';
11
-
12
-
13
- import useHookFormMaskAntd from './useHookFormMaskAntd';
14
-
15
- import type { InputRef } from 'antd';
16
- import type {
17
- FieldValues,
18
- UseFormRegister,
19
- } from 'react-hook-form';
20
-
21
- vi.mock('../core', () => ({
22
- applyMaskToElement: vi.fn(),
23
- resolveInputRef: vi.fn(),
24
- }));
25
-
26
- function makeRegisterFn(name = 'test') {
27
- return vi.fn(() => ({
28
- ref: vi.fn(),
29
- onChange: vi.fn(),
30
- onBlur: vi.fn(),
31
- name,
32
- }));
33
- }
34
-
35
- describe('useHookFormMaskAntd', () => {
36
- beforeEach(() => {
37
- vi.clearAllMocks();
38
- });
39
-
40
- it('returns a function', () => {
41
- const registerFn = makeRegisterFn();
42
- const { result } = renderHook(
43
- () => useHookFormMaskAntd(registerFn as UseFormRegister<FieldValues>),
44
- );
45
- expect(typeof result.current).toBe('function');
46
- });
47
-
48
- it('throws when registerFn is missing', () => {
49
- const { result } = renderHook(
50
- () => useHookFormMaskAntd(undefined as unknown as UseFormRegister<FieldValues>),
51
- );
52
- expect(() => result.current('field' as never, '999-999'))
53
- .toThrowError('registerFn is required');
54
- });
55
-
56
- it('registers field with mask and calls core helpers', () => {
57
- const inputElement = document.createElement('input');
58
- const prevRef = vi.fn();
59
- const registerFn = vi.fn(() => ({
60
- ref: prevRef,
61
- onChange: vi.fn(),
62
- onBlur: vi.fn(),
63
- name: 'phone',
64
- }));
65
-
66
- vi.mocked(resolveInputRef).mockReturnValue(inputElement);
67
-
68
- const { result } = renderHook(
69
- () => useHookFormMaskAntd(registerFn as UseFormRegister<FieldValues>),
70
- );
71
- const options = { placeholder: '_' } as never;
72
- const registration = result.current('phone' as never, '999-999', options);
73
-
74
- expect(registerFn).toHaveBeenCalledWith('phone', options);
75
- expect(registration.ref).toBeDefined();
76
- expect(typeof registration.ref).toBe('function');
77
-
78
- registration.ref({ input: inputElement } as unknown as InputRef);
79
-
80
- expect(resolveInputRef).toHaveBeenCalledWith(inputElement);
81
- expect(applyMaskToElement).toHaveBeenCalledWith(inputElement, '999-999', options);
82
- expect(prevRef).toHaveBeenCalledWith(inputElement);
83
- });
84
-
85
- it('handles null ref from register', () => {
86
- const registerFn = vi.fn(() => ({
87
- ref: undefined,
88
- onChange: vi.fn(),
89
- onBlur: vi.fn(),
90
- name: 'phone',
91
- }));
92
-
93
- const { result } = renderHook(
94
- () => useHookFormMaskAntd(registerFn as unknown as UseFormRegister<FieldValues>),
95
- );
96
- const registration = result.current('phone' as never, '999-999');
97
-
98
- expect(registration.ref).toBeDefined();
99
-
100
- const inputElement = document.createElement('input');
101
- vi.mocked(resolveInputRef).mockReturnValue(inputElement);
102
-
103
- registration.ref({ input: inputElement } as unknown as InputRef);
104
-
105
- expect(applyMaskToElement).toHaveBeenCalled();
106
- });
107
-
108
- it('preserves register return properties and defines non-enumerable prevRef', () => {
109
- const onChange = vi.fn();
110
- const onBlur = vi.fn();
111
- const prevRef = vi.fn();
112
- const registerFn = vi.fn(() => ({
113
- ref: prevRef,
114
- onChange,
115
- onBlur,
116
- name: 'phone',
117
- }));
118
-
119
- const { result } = renderHook(
120
- () => useHookFormMaskAntd(registerFn as UseFormRegister<FieldValues>),
121
- );
122
- const registration = result.current('phone' as never, '999-999');
123
-
124
- expect(registration.onChange).toBe(onChange);
125
- expect(registration.onBlur).toBe(onBlur);
126
- expect(registration.name).toBe('phone');
127
-
128
- const descriptor = Object.getOwnPropertyDescriptor(registration, 'prevRef');
129
- expect(descriptor?.enumerable).toBe(false);
130
- expect((registration as unknown as { prevRef: typeof prevRef }).prevRef).toBe(prevRef);
131
- });
132
-
133
- it('returns the same ref callback reference across multiple calls (stable identity)', () => {
134
- const registerFn = makeRegisterFn('phone');
135
-
136
- const { result } = renderHook(
137
- () => useHookFormMaskAntd(registerFn as UseFormRegister<FieldValues>),
138
- );
139
-
140
- const first = result.current('phone' as never, '999-999');
141
- const second = result.current('phone' as never, '999-999');
142
-
143
- expect(first.ref).toBe(second.ref);
144
- });
145
-
146
- it('returns different ref callbacks for different field/mask combinations', () => {
147
- const registerFn = vi.fn((name: string) => ({
148
- ref: vi.fn(),
149
- onChange: vi.fn(),
150
- onBlur: vi.fn(),
151
- name,
152
- }));
153
-
154
- const { result } = renderHook(
155
- () => useHookFormMaskAntd(registerFn as unknown as UseFormRegister<FieldValues>),
156
- );
157
-
158
- const phone = result.current('phone' as never, '999-999');
159
- const cpf = result.current('cpf' as never, 'cpf');
160
-
161
- expect(phone.ref).not.toBe(cpf.ref);
162
- });
163
-
164
- it('invalidates the ref cache when registerFn changes (rerender with new registerFn)', () => {
165
- const registerFn1 = makeRegisterFn('phone');
166
- const registerFn2 = makeRegisterFn('phone');
167
-
168
- const { result, rerender } = renderHook(
169
- ({ fn }) => useHookFormMaskAntd(fn as UseFormRegister<FieldValues>),
170
- { initialProps: { fn: registerFn1 } },
171
- );
172
-
173
- const refBefore = result.current('phone' as never, '999-999').ref;
174
-
175
- rerender({ fn: registerFn2 });
176
-
177
- const refAfter = result.current('phone' as never, '999-999').ref;
178
-
179
- expect(refBefore).not.toBe(refAfter);
180
- });
181
- });
@@ -1,37 +0,0 @@
1
- import { act, renderHook } from '@testing-library/react';
2
- import {
3
- beforeEach,
4
- describe,
5
- expect,
6
- it,
7
- vi,
8
- } from 'vitest';
9
-
10
- import type { InputRef } from 'antd';
11
-
12
- vi.mock('../utils/isServer', () => ({
13
- default: true,
14
- }));
15
-
16
- describe('useMaskInputAntd server-side', () => {
17
- beforeEach(() => {
18
- vi.clearAllMocks();
19
- vi.resetModules();
20
- });
21
-
22
- it('returns no-op function on server', async () => {
23
- const { default: useMaskInputAntd } = await import('./useMaskInputAntd');
24
- const { result } = renderHook(
25
- () => useMaskInputAntd({ mask: '999-999' }),
26
- );
27
-
28
- expect(typeof result.current).toBe('function');
29
-
30
- act(() => {
31
- result.current({ input: document.createElement('input') } as InputRef);
32
- });
33
-
34
- // should do nothing on server
35
- expect(result.current).toBeDefined();
36
- });
37
- });
@@ -1,131 +0,0 @@
1
- import { act, renderHook } from '@testing-library/react';
2
- import inputmask from 'inputmask';
3
- import {
4
- beforeEach,
5
- describe,
6
- expect,
7
- it,
8
- vi,
9
- } from 'vitest';
10
-
11
- import useMaskInputAntd from './useMaskInputAntd';
12
-
13
- import type { InputRef } from 'antd';
14
-
15
- vi.mock('inputmask', () => ({
16
- default: vi.fn((options) => ({
17
- mask: vi.fn(),
18
- options,
19
- })),
20
- }));
21
-
22
- vi.mock('../utils/isServer', () => ({
23
- default: false,
24
- }));
25
-
26
- describe('useMaskInputAntd', () => {
27
- beforeEach(() => {
28
- vi.clearAllMocks();
29
- });
30
-
31
- it('returns a ref callback function', () => {
32
- const { result } = renderHook(() => useMaskInputAntd({ mask: '999-999' }));
33
- expect(typeof result.current).toBe('function');
34
- expect(typeof result.current.unmaskedValue).toBe('function');
35
- });
36
-
37
- it('handles null input ref', () => {
38
- const { result } = renderHook(() => useMaskInputAntd({ mask: '999-999' }));
39
-
40
- act(() => {
41
- result.current(null);
42
- });
43
-
44
- expect(result.current).toBeDefined();
45
- });
46
-
47
- it('applies mask to element when given InputRef with input element', () => {
48
- const inputElement = document.createElement('input');
49
- vi.mocked(inputmask).mockReturnValue({
50
- mask: vi.fn(),
51
- } as any);
52
-
53
- const { result, rerender } = renderHook(
54
- () => useMaskInputAntd({ mask: '999-999' }),
55
- );
56
-
57
- act(() => {
58
- result.current({ input: inputElement } as unknown as InputRef);
59
- });
60
-
61
- rerender();
62
-
63
- expect(inputmask).toHaveBeenCalled();
64
- });
65
-
66
- it('exposes the unmasked value from the masked Ant Design input', () => {
67
- const inputElement = document.createElement('input');
68
- vi.mocked(inputmask).mockReturnValue({
69
- mask: vi.fn(),
70
- } as any);
71
-
72
- const { result } = renderHook(
73
- () => useMaskInputAntd({ mask: '999-999' }),
74
- );
75
-
76
- act(() => {
77
- result.current({ input: inputElement } as unknown as InputRef);
78
- });
79
-
80
- inputElement.inputmask = {
81
- unmaskedvalue: vi.fn(() => '2026-04-01'),
82
- } as any;
83
-
84
- expect(result.current.unmaskedValue()).toBe('2026-04-01');
85
- });
86
-
87
- it('works with custom options', () => {
88
- const inputElement = document.createElement('input');
89
- vi.mocked(inputmask).mockReturnValue({
90
- mask: vi.fn(),
91
- } as any);
92
-
93
- const { result, rerender } = renderHook(
94
- () => useMaskInputAntd({
95
- mask: '999-999',
96
- options: { placeholder: '_' },
97
- }),
98
- );
99
-
100
- act(() => {
101
- result.current({ input: inputElement } as unknown as InputRef);
102
- });
103
-
104
- rerender();
105
-
106
- expect(inputmask).toHaveBeenCalled();
107
- });
108
-
109
- it('accepts register option and applies mask', () => {
110
- const inputElement = document.createElement('input');
111
- const register = vi.fn();
112
- vi.mocked(inputmask).mockReturnValue({
113
- mask: vi.fn(),
114
- } as any);
115
-
116
- const { result, rerender } = renderHook(
117
- () => useMaskInputAntd({
118
- mask: '999-999',
119
- register,
120
- }),
121
- );
122
-
123
- act(() => {
124
- result.current({ input: inputElement } as unknown as InputRef);
125
- });
126
-
127
- rerender();
128
-
129
- expect(inputmask).toHaveBeenCalled();
130
- });
131
- });