use-mask-input 3.8.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +55 -7
- package/dist/antd.d.cts +1 -1
- package/dist/antd.d.ts +1 -1
- package/dist/{index-S8txl6uK.d.cts → index-BoaVtWUr.d.cts} +10 -1
- package/dist/{index-S8txl6uK.d.ts → index-BoaVtWUr.d.ts} +10 -1
- package/dist/index.cjs +51 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +50 -5
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/api/index.ts +2 -0
- package/src/api/useTanStackFormMask.ts +24 -0
- package/src/api/withTanStackFormMask.spec.ts +76 -0
- package/src/api/withTanStackFormMask.ts +64 -0
- package/src/core/maskEngine.spec.ts +12 -6
- package/src/index.tsx +4 -0
- package/src/types/index.ts +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
## [3.6.0](https://github.com/eduardoborges/use-mask-input/compare/3.5.2...3.6.0) (2026-01-13)
|
|
2
2
|
|
|
3
|
+
## 3.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 99e7a0a: Add TanStack Form integration: `useTanStackFormMask` and `withTanStackFormMask`, with types `TanStackFormInputProps` and `UseTanStackFormMaskReturn`. Documentation and a `tanstack-form-project` demo app were added; examples favor international-friendly masks (phone, email, postal).
|
|
8
|
+
|
|
3
9
|
## 3.8.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<h1
|
|
3
|
-
<p>Input masks for React.
|
|
2
|
+
<h1>🥸 use-mask-input</h1>
|
|
3
|
+
<p>Input masks for React. Works with React Hook Form, <strong>TanStack Form</strong>, Ant Design, and plain inputs.</p>
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/use-mask-input)
|
|
6
6
|
[](https://www.npmjs.com/package/use-mask-input)
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
**[Documentation](http://use-mask-input.eduardoborges.dev)** · **[API Reference](http://use-mask-input.eduardoborges.dev/api-reference)** · **[Sponsor](https://ko-fi.com/E1E71VQENQ)**
|
|
15
|
+
**[Documentation](http://use-mask-input.eduardoborges.dev)** · **[API Reference](http://use-mask-input.eduardoborges.dev/api-reference)** · **[TanStack Form](http://use-mask-input.eduardoborges.dev/tanstack-form)** · **[Sponsor](https://ko-fi.com/E1E71VQENQ)**
|
|
16
16
|
|
|
17
17
|
## Install
|
|
18
18
|
|
|
@@ -44,21 +44,66 @@ function MyForm() {
|
|
|
44
44
|
return (
|
|
45
45
|
<form onSubmit={handleSubmit(console.log)}>
|
|
46
46
|
<input {...registerWithMask('phone', '(99) 99999-9999')} />
|
|
47
|
-
<input {...registerWithMask('
|
|
47
|
+
<input {...registerWithMask('email', 'email')} />
|
|
48
48
|
<button type="submit">Submit</button>
|
|
49
49
|
</form>
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
### With TanStack Form
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { useForm } from '@tanstack/react-form';
|
|
58
|
+
import { useTanStackFormMask } from 'use-mask-input';
|
|
59
|
+
|
|
60
|
+
function MyForm() {
|
|
61
|
+
const maskField = useTanStackFormMask();
|
|
62
|
+
const form = useForm({
|
|
63
|
+
defaultValues: {
|
|
64
|
+
phone: '',
|
|
65
|
+
},
|
|
66
|
+
onSubmit: async ({ value }) => {
|
|
67
|
+
console.log(value);
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<form
|
|
73
|
+
onSubmit={(event) => {
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
event.stopPropagation();
|
|
76
|
+
void form.handleSubmit();
|
|
77
|
+
}}
|
|
78
|
+
>
|
|
79
|
+
<form.Field name="phone">
|
|
80
|
+
{(field) => {
|
|
81
|
+
const inputProps = maskField(
|
|
82
|
+
'(99) 99999-9999',
|
|
83
|
+
{
|
|
84
|
+
name: field.name,
|
|
85
|
+
value: field.state.value,
|
|
86
|
+
onBlur: field.handleBlur,
|
|
87
|
+
onChange: (event) => field.handleChange(event.target.value),
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
return <input {...inputProps} placeholder="(00) 00000-0000" />;
|
|
92
|
+
}}
|
|
93
|
+
</form.Field>
|
|
94
|
+
</form>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
54
99
|
### With Ant Design
|
|
55
100
|
|
|
56
101
|
```tsx
|
|
57
102
|
import { Input } from 'antd';
|
|
58
103
|
import { useMaskInputAntd } from 'use-mask-input/antd';
|
|
59
104
|
|
|
60
|
-
function
|
|
61
|
-
const ref = useMaskInputAntd({ mask: '
|
|
105
|
+
function EmailInput() {
|
|
106
|
+
const ref = useMaskInputAntd({ mask: 'email' });
|
|
62
107
|
return <Input ref={ref} />;
|
|
63
108
|
}
|
|
64
109
|
```
|
|
@@ -69,8 +114,10 @@ function CPFInput() {
|
|
|
69
114
|
|-----|-------------|
|
|
70
115
|
| `useMaskInput` | Hook. Returns a ref callback. Default choice. |
|
|
71
116
|
| `useHookFormMask` | Hook. Wraps React Hook Form's `register`. |
|
|
117
|
+
| `useTanStackFormMask` | Hook. Adds mask to TanStack Form field input props. |
|
|
72
118
|
| `withMask` | Function. Ref callback. Requires `React.memo`. |
|
|
73
119
|
| `withHookFormMask` | Function. Mask for registered fields. Requires `React.memo`. |
|
|
120
|
+
| `withTanStackFormMask` | Function. Mask for TanStack input props. Requires `React.memo`. |
|
|
74
121
|
| `useMaskInputAntd` | Hook. `useMaskInput` for Ant Design. |
|
|
75
122
|
| `useHookFormMaskAntd` | Hook. `useHookFormMask` for Ant Design. |
|
|
76
123
|
|
|
@@ -80,8 +127,9 @@ function CPFInput() {
|
|
|
80
127
|
|
|
81
128
|
## Works With
|
|
82
129
|
|
|
130
|
+
- **TanStack Form** (`useTanStackFormMask`, `withTanStackFormMask`). See the [TanStack Form guide](http://use-mask-input.eduardoborges.dev/tanstack-form).
|
|
83
131
|
- React Hook Form
|
|
84
|
-
- Ant Design
|
|
132
|
+
- Ant Design (`use-mask-input/antd`)
|
|
85
133
|
- React Final Form
|
|
86
134
|
- Next.js / SSR
|
|
87
135
|
|
package/dist/antd.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { InputRef } from 'antd';
|
|
2
2
|
import { RefCallback } from 'react';
|
|
3
3
|
import { FieldValues, RegisterOptions, UseFormRegister, Path } from 'react-hook-form';
|
|
4
|
-
import { U as UseHookFormMaskReturn, M as Mask, O as Options } from './index-
|
|
4
|
+
import { U as UseHookFormMaskReturn, M as Mask, O as Options } from './index-BoaVtWUr.cjs';
|
|
5
5
|
|
|
6
6
|
type UseHookFormMaskAntdReturn<T extends FieldValues> = Omit<UseHookFormMaskReturn<T>, 'ref'> & {
|
|
7
7
|
ref: RefCallback<InputRef | null>;
|
package/dist/antd.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { InputRef } from 'antd';
|
|
2
2
|
import { RefCallback } from 'react';
|
|
3
3
|
import { FieldValues, RegisterOptions, UseFormRegister, Path } from 'react-hook-form';
|
|
4
|
-
import { U as UseHookFormMaskReturn, M as Mask, O as Options } from './index-
|
|
4
|
+
import { U as UseHookFormMaskReturn, M as Mask, O as Options } from './index-BoaVtWUr.js';
|
|
5
5
|
|
|
6
6
|
type UseHookFormMaskAntdReturn<T extends FieldValues> = Omit<UseHookFormMaskReturn<T>, 'ref'> & {
|
|
7
7
|
ref: RefCallback<InputRef | null>;
|
|
@@ -579,5 +579,14 @@ interface UseHookFormMaskReturn<T extends FieldValues> extends UseFormRegisterRe
|
|
|
579
579
|
ref: RefCallback<HTMLElement | null>;
|
|
580
580
|
prevRef: RefCallback<HTMLElement | null>;
|
|
581
581
|
}
|
|
582
|
+
interface TanStackFormInputProps {
|
|
583
|
+
name?: string;
|
|
584
|
+
ref?: RefCallback<HTMLElement | null>;
|
|
585
|
+
[key: string]: unknown;
|
|
586
|
+
}
|
|
587
|
+
type UseTanStackFormMaskReturn<T extends TanStackFormInputProps = TanStackFormInputProps> = Omit<T, 'ref'> & {
|
|
588
|
+
ref: RefCallback<HTMLElement | null>;
|
|
589
|
+
prevRef: RefCallback<HTMLElement | null> | undefined;
|
|
590
|
+
};
|
|
582
591
|
|
|
583
|
-
export type { Input as I, Mask as M, Options as O, UseHookFormMaskReturn as U };
|
|
592
|
+
export type { Input as I, Mask as M, Options as O, TanStackFormInputProps as T, UseHookFormMaskReturn as U, UseTanStackFormMaskReturn as a };
|
|
@@ -579,5 +579,14 @@ interface UseHookFormMaskReturn<T extends FieldValues> extends UseFormRegisterRe
|
|
|
579
579
|
ref: RefCallback<HTMLElement | null>;
|
|
580
580
|
prevRef: RefCallback<HTMLElement | null>;
|
|
581
581
|
}
|
|
582
|
+
interface TanStackFormInputProps {
|
|
583
|
+
name?: string;
|
|
584
|
+
ref?: RefCallback<HTMLElement | null>;
|
|
585
|
+
[key: string]: unknown;
|
|
586
|
+
}
|
|
587
|
+
type UseTanStackFormMaskReturn<T extends TanStackFormInputProps = TanStackFormInputProps> = Omit<T, 'ref'> & {
|
|
588
|
+
ref: RefCallback<HTMLElement | null>;
|
|
589
|
+
prevRef: RefCallback<HTMLElement | null> | undefined;
|
|
590
|
+
};
|
|
582
591
|
|
|
583
|
-
export type { Input as I, Mask as M, Options as O, UseHookFormMaskReturn as U };
|
|
592
|
+
export type { Input as I, Mask as M, Options as O, TanStackFormInputProps as T, UseHookFormMaskReturn as U, UseTanStackFormMaskReturn as a };
|
package/dist/index.cjs
CHANGED
|
@@ -74,8 +74,53 @@ function useHookFormMask(registerFn) {
|
|
|
74
74
|
}, [registerFn]);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
// src/api/
|
|
77
|
+
// src/api/withTanStackFormMask.ts
|
|
78
78
|
var refCache = /* @__PURE__ */ new WeakMap();
|
|
79
|
+
function withTanStackFormMask(inputProps, mask, options) {
|
|
80
|
+
const { ref } = inputProps;
|
|
81
|
+
if (!ref) {
|
|
82
|
+
const result2 = {
|
|
83
|
+
...inputProps,
|
|
84
|
+
ref: ((input) => {
|
|
85
|
+
if (input) chunkX5SEJVSB_cjs.applyMaskToElement(input, mask, options);
|
|
86
|
+
})
|
|
87
|
+
};
|
|
88
|
+
chunkX5SEJVSB_cjs.setPrevRef(result2, ref);
|
|
89
|
+
return result2;
|
|
90
|
+
}
|
|
91
|
+
if (!refCache.has(ref)) {
|
|
92
|
+
refCache.set(ref, /* @__PURE__ */ new Map());
|
|
93
|
+
}
|
|
94
|
+
const maskCache = refCache.get(ref);
|
|
95
|
+
const cacheKey = chunkX5SEJVSB_cjs.makeMaskCacheKey(inputProps.name ?? "", mask);
|
|
96
|
+
if (!maskCache?.has(cacheKey)) {
|
|
97
|
+
const applyMaskToRef = (_ref) => {
|
|
98
|
+
if (_ref) chunkX5SEJVSB_cjs.applyMaskToElement(_ref, mask, options);
|
|
99
|
+
return _ref;
|
|
100
|
+
};
|
|
101
|
+
maskCache?.set(
|
|
102
|
+
cacheKey,
|
|
103
|
+
chunkX5SEJVSB_cjs.flow(applyMaskToRef, ref)
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
const result = {
|
|
107
|
+
...inputProps,
|
|
108
|
+
ref: maskCache?.get(cacheKey)
|
|
109
|
+
};
|
|
110
|
+
chunkX5SEJVSB_cjs.setPrevRef(result, ref);
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/api/useTanStackFormMask.ts
|
|
115
|
+
function useTanStackFormMask() {
|
|
116
|
+
return react.useMemo(
|
|
117
|
+
() => (mask, inputProps, options) => withTanStackFormMask(inputProps, mask, options),
|
|
118
|
+
[]
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/api/withHookFormMask.ts
|
|
123
|
+
var refCache2 = /* @__PURE__ */ new WeakMap();
|
|
79
124
|
function withHookFormMask(register, mask, options) {
|
|
80
125
|
const { ref } = register;
|
|
81
126
|
if (!ref) {
|
|
@@ -86,10 +131,10 @@ function withHookFormMask(register, mask, options) {
|
|
|
86
131
|
chunkX5SEJVSB_cjs.setPrevRef(result2, ref);
|
|
87
132
|
return result2;
|
|
88
133
|
}
|
|
89
|
-
if (!
|
|
90
|
-
|
|
134
|
+
if (!refCache2.has(ref)) {
|
|
135
|
+
refCache2.set(ref, /* @__PURE__ */ new Map());
|
|
91
136
|
}
|
|
92
|
-
const maskCache =
|
|
137
|
+
const maskCache = refCache2.get(ref);
|
|
93
138
|
const cacheKey = chunkX5SEJVSB_cjs.makeMaskCacheKey(register.name, mask);
|
|
94
139
|
if (!maskCache?.has(cacheKey)) {
|
|
95
140
|
const applyMaskToRef = (_ref) => {
|
|
@@ -115,6 +160,8 @@ Object.defineProperty(exports, "withMask", {
|
|
|
115
160
|
});
|
|
116
161
|
exports.useHookFormMask = useHookFormMask;
|
|
117
162
|
exports.useMaskInput = useMaskInput;
|
|
163
|
+
exports.useTanStackFormMask = useTanStackFormMask;
|
|
118
164
|
exports.withHookFormMask = withHookFormMask;
|
|
165
|
+
exports.withTanStackFormMask = withTanStackFormMask;
|
|
119
166
|
//# sourceMappingURL=index.cjs.map
|
|
120
167
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/useMaskInput.ts","../src/api/useHookFormMask.ts","../src/api/withHookFormMask.ts"],"names":["useRef","useCallback","resolveInputRef","withMask","useEffect","isServer_default","useLayoutEffect","useMemo","makeMaskCacheKey","applyMaskToElement","flow","setPrevRef","result"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n useCallback, useEffect, useRef,\n} from 'react';\n\nimport { resolveInputRef } from '../core';\nimport withMask from './withMask';\nimport isServer from '../utils/isServer';\n\nimport type { Input, Mask, Options } 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): ((input: Input | null) => void) {\n const { mask, register, options } = props;\n const ref = useRef<HTMLInputElement | null>(null);\n const maskRef = useRef(mask);\n const optionsRef = useRef(options);\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 return (): void => {\n // server doesn't have dom, so just do nothing\n };\n }\n\n return refCallback;\n}\n","import { useLayoutEffect, useMemo, useRef } from 'react';\n\nimport { applyMaskToElement } from '../core';\nimport { flow, makeMaskCacheKey, setPrevRef } 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\n setPrevRef(result, ref);\n\n return result;\n };\n }, [registerFn]);\n}\n","import { applyMaskToElement } from '../core';\nimport { flow, makeMaskCacheKey, setPrevRef } 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\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 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 applyMaskToRef = (_ref: HTMLElement | null) => {\n if (_ref) applyMaskToElement(_ref, mask, options);\n return _ref;\n };\n maskCache?.set(\n cacheKey,\n flow(applyMaskToRef, ref) as RefCallback<HTMLElement | null>,\n );\n }\n\n const result = {\n ...register,\n ref: maskCache?.get(cacheKey),\n } as UseHookFormMaskReturn<FieldValues>;\n\n setPrevRef(result, ref);\n\n return result;\n}\n"]}
|
|
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","useCallback","resolveInputRef","withMask","useEffect","isServer_default","useLayoutEffect","useMemo","makeMaskCacheKey","applyMaskToElement","flow","setPrevRef","result","refCache"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n useCallback, useEffect, useRef,\n} from 'react';\n\nimport { resolveInputRef } from '../core';\nimport withMask from './withMask';\nimport isServer from '../utils/isServer';\n\nimport type { Input, Mask, Options } 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): ((input: Input | null) => void) {\n const { mask, register, options } = props;\n const ref = useRef<HTMLInputElement | null>(null);\n const maskRef = useRef(mask);\n const optionsRef = useRef(options);\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 return (): void => {\n // server doesn't have dom, so just do nothing\n };\n }\n\n return refCallback;\n}\n","import { useLayoutEffect, useMemo, useRef } from 'react';\n\nimport { applyMaskToElement } from '../core';\nimport { flow, makeMaskCacheKey, setPrevRef } 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\n setPrevRef(result, ref);\n\n return result;\n };\n }, [registerFn]);\n}\n","import { applyMaskToElement } from '../core';\nimport { flow, makeMaskCacheKey, setPrevRef } from '../utils';\n\nimport type { RefCallback } from 'react';\n\nimport type {\n Mask, Options, TanStackFormInputProps, UseTanStackFormMaskReturn,\n} from '../types';\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 const result = {\n ...inputProps,\n ref: ((input: HTMLElement | null) => {\n if (input) applyMaskToElement(input, mask, options);\n }) as RefCallback<HTMLElement | null>,\n } as unknown as UseTanStackFormMaskReturn<T>;\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 applyMaskToRef = (_ref: HTMLElement | null) => {\n if (_ref) applyMaskToElement(_ref, mask, options);\n return _ref;\n };\n\n maskCache?.set(\n cacheKey,\n flow(applyMaskToRef, ref) as RefCallback<HTMLElement | null>,\n );\n }\n\n const result = {\n ...inputProps,\n ref: maskCache?.get(cacheKey),\n } as unknown as UseTanStackFormMaskReturn<T>;\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 { flow, makeMaskCacheKey, setPrevRef } 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\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 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 applyMaskToRef = (_ref: HTMLElement | null) => {\n if (_ref) applyMaskToElement(_ref, mask, options);\n return _ref;\n };\n maskCache?.set(\n cacheKey,\n flow(applyMaskToRef, ref) as RefCallback<HTMLElement | null>,\n );\n }\n\n const result = {\n ...register,\n ref: maskCache?.get(cacheKey),\n } as UseHookFormMaskReturn<FieldValues>;\n\n setPrevRef(result, ref);\n\n return result;\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as Mask, O as Options, I as Input, U as UseHookFormMaskReturn } from './index-
|
|
1
|
+
import { M as Mask, O as Options, I as Input, U as UseHookFormMaskReturn, T as TanStackFormInputProps, a as UseTanStackFormMaskReturn } from './index-BoaVtWUr.cjs';
|
|
2
2
|
import { FieldValues, RegisterOptions, UseFormRegister, Path, UseFormRegisterReturn } from 'react-hook-form';
|
|
3
3
|
export { UseFormRegister, UseFormRegisterReturn } from 'react-hook-form';
|
|
4
4
|
import 'react';
|
|
@@ -31,6 +31,12 @@ declare function useMaskInput(props: UseMaskInputOptions): ((input: Input | null
|
|
|
31
31
|
*/
|
|
32
32
|
declare function useHookFormMask<T extends FieldValues, D extends RegisterOptions>(registerFn: UseFormRegister<T>): ((fieldName: Path<T>, mask: Mask, options?: (D & Options) | Options | D) => UseHookFormMaskReturn<T>);
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Creates a helper to mask TanStack Form-compatible input props.
|
|
36
|
+
* Designed for objects returned by field.getInputProps().
|
|
37
|
+
*/
|
|
38
|
+
declare function useTanStackFormMask(): <T extends TanStackFormInputProps>(mask: Mask, inputProps: T, options?: Options) => UseTanStackFormMaskReturn<T>;
|
|
39
|
+
|
|
34
40
|
/**
|
|
35
41
|
* Higher-order function that creates a ref callback for applying input masks.
|
|
36
42
|
* Simple function to apply mask via ref. No hooks, no drama.
|
|
@@ -53,4 +59,10 @@ declare function withMask(mask: Mask, options?: Options): ((input: Input | null)
|
|
|
53
59
|
*/
|
|
54
60
|
declare function withHookFormMask(register: UseFormRegisterReturn, mask: Mask, options?: Options): UseHookFormMaskReturn<FieldValues>;
|
|
55
61
|
|
|
56
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Enhances TanStack Form-compatible input props with mask support.
|
|
64
|
+
* Works with objects returned by field.getInputProps().
|
|
65
|
+
*/
|
|
66
|
+
declare function withTanStackFormMask<T extends TanStackFormInputProps>(inputProps: T, mask: Mask, options?: Options): UseTanStackFormMaskReturn<T>;
|
|
67
|
+
|
|
68
|
+
export { Input, Mask, Options, TanStackFormInputProps, UseTanStackFormMaskReturn, useHookFormMask, useMaskInput, useTanStackFormMask, withHookFormMask, withMask, withTanStackFormMask };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as Mask, O as Options, I as Input, U as UseHookFormMaskReturn } from './index-
|
|
1
|
+
import { M as Mask, O as Options, I as Input, U as UseHookFormMaskReturn, T as TanStackFormInputProps, a as UseTanStackFormMaskReturn } from './index-BoaVtWUr.js';
|
|
2
2
|
import { FieldValues, RegisterOptions, UseFormRegister, Path, UseFormRegisterReturn } from 'react-hook-form';
|
|
3
3
|
export { UseFormRegister, UseFormRegisterReturn } from 'react-hook-form';
|
|
4
4
|
import 'react';
|
|
@@ -31,6 +31,12 @@ declare function useMaskInput(props: UseMaskInputOptions): ((input: Input | null
|
|
|
31
31
|
*/
|
|
32
32
|
declare function useHookFormMask<T extends FieldValues, D extends RegisterOptions>(registerFn: UseFormRegister<T>): ((fieldName: Path<T>, mask: Mask, options?: (D & Options) | Options | D) => UseHookFormMaskReturn<T>);
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Creates a helper to mask TanStack Form-compatible input props.
|
|
36
|
+
* Designed for objects returned by field.getInputProps().
|
|
37
|
+
*/
|
|
38
|
+
declare function useTanStackFormMask(): <T extends TanStackFormInputProps>(mask: Mask, inputProps: T, options?: Options) => UseTanStackFormMaskReturn<T>;
|
|
39
|
+
|
|
34
40
|
/**
|
|
35
41
|
* Higher-order function that creates a ref callback for applying input masks.
|
|
36
42
|
* Simple function to apply mask via ref. No hooks, no drama.
|
|
@@ -53,4 +59,10 @@ declare function withMask(mask: Mask, options?: Options): ((input: Input | null)
|
|
|
53
59
|
*/
|
|
54
60
|
declare function withHookFormMask(register: UseFormRegisterReturn, mask: Mask, options?: Options): UseHookFormMaskReturn<FieldValues>;
|
|
55
61
|
|
|
56
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Enhances TanStack Form-compatible input props with mask support.
|
|
64
|
+
* Works with objects returned by field.getInputProps().
|
|
65
|
+
*/
|
|
66
|
+
declare function withTanStackFormMask<T extends TanStackFormInputProps>(inputProps: T, mask: Mask, options?: Options): UseTanStackFormMaskReturn<T>;
|
|
67
|
+
|
|
68
|
+
export { Input, Mask, Options, TanStackFormInputProps, UseTanStackFormMaskReturn, useHookFormMask, useMaskInput, useTanStackFormMask, withHookFormMask, withMask, withTanStackFormMask };
|
package/dist/index.js
CHANGED
|
@@ -73,8 +73,53 @@ function useHookFormMask(registerFn) {
|
|
|
73
73
|
}, [registerFn]);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// src/api/
|
|
76
|
+
// src/api/withTanStackFormMask.ts
|
|
77
77
|
var refCache = /* @__PURE__ */ new WeakMap();
|
|
78
|
+
function withTanStackFormMask(inputProps, mask, options) {
|
|
79
|
+
const { ref } = inputProps;
|
|
80
|
+
if (!ref) {
|
|
81
|
+
const result2 = {
|
|
82
|
+
...inputProps,
|
|
83
|
+
ref: ((input) => {
|
|
84
|
+
if (input) applyMaskToElement(input, mask, options);
|
|
85
|
+
})
|
|
86
|
+
};
|
|
87
|
+
setPrevRef(result2, ref);
|
|
88
|
+
return result2;
|
|
89
|
+
}
|
|
90
|
+
if (!refCache.has(ref)) {
|
|
91
|
+
refCache.set(ref, /* @__PURE__ */ new Map());
|
|
92
|
+
}
|
|
93
|
+
const maskCache = refCache.get(ref);
|
|
94
|
+
const cacheKey = makeMaskCacheKey(inputProps.name ?? "", mask);
|
|
95
|
+
if (!maskCache?.has(cacheKey)) {
|
|
96
|
+
const applyMaskToRef = (_ref) => {
|
|
97
|
+
if (_ref) applyMaskToElement(_ref, mask, options);
|
|
98
|
+
return _ref;
|
|
99
|
+
};
|
|
100
|
+
maskCache?.set(
|
|
101
|
+
cacheKey,
|
|
102
|
+
flow(applyMaskToRef, ref)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const result = {
|
|
106
|
+
...inputProps,
|
|
107
|
+
ref: maskCache?.get(cacheKey)
|
|
108
|
+
};
|
|
109
|
+
setPrevRef(result, ref);
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/api/useTanStackFormMask.ts
|
|
114
|
+
function useTanStackFormMask() {
|
|
115
|
+
return useMemo(
|
|
116
|
+
() => (mask, inputProps, options) => withTanStackFormMask(inputProps, mask, options),
|
|
117
|
+
[]
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/api/withHookFormMask.ts
|
|
122
|
+
var refCache2 = /* @__PURE__ */ new WeakMap();
|
|
78
123
|
function withHookFormMask(register, mask, options) {
|
|
79
124
|
const { ref } = register;
|
|
80
125
|
if (!ref) {
|
|
@@ -85,10 +130,10 @@ function withHookFormMask(register, mask, options) {
|
|
|
85
130
|
setPrevRef(result2, ref);
|
|
86
131
|
return result2;
|
|
87
132
|
}
|
|
88
|
-
if (!
|
|
89
|
-
|
|
133
|
+
if (!refCache2.has(ref)) {
|
|
134
|
+
refCache2.set(ref, /* @__PURE__ */ new Map());
|
|
90
135
|
}
|
|
91
|
-
const maskCache =
|
|
136
|
+
const maskCache = refCache2.get(ref);
|
|
92
137
|
const cacheKey = makeMaskCacheKey(register.name, mask);
|
|
93
138
|
if (!maskCache?.has(cacheKey)) {
|
|
94
139
|
const applyMaskToRef = (_ref) => {
|
|
@@ -108,6 +153,6 @@ function withHookFormMask(register, mask, options) {
|
|
|
108
153
|
return result;
|
|
109
154
|
}
|
|
110
155
|
|
|
111
|
-
export { useHookFormMask, useMaskInput, withHookFormMask };
|
|
156
|
+
export { useHookFormMask, useMaskInput, useTanStackFormMask, withHookFormMask, withTanStackFormMask };
|
|
112
157
|
//# sourceMappingURL=index.js.map
|
|
113
158
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/useMaskInput.ts","../src/api/useHookFormMask.ts","../src/api/withHookFormMask.ts"],"names":["useRef","result"],"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';\n\nimport type { Input, Mask, Options } 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): ((input: Input | null) => void) {\n const { mask, register, options } = props;\n const ref = useRef<HTMLInputElement | null>(null);\n const maskRef = useRef(mask);\n const optionsRef = useRef(options);\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 return (): void => {\n // server doesn't have dom, so just do nothing\n };\n }\n\n return refCallback;\n}\n","import { useLayoutEffect, useMemo, useRef } from 'react';\n\nimport { applyMaskToElement } from '../core';\nimport { flow, makeMaskCacheKey, setPrevRef } 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\n setPrevRef(result, ref);\n\n return result;\n };\n }, [registerFn]);\n}\n","import { applyMaskToElement } from '../core';\nimport { flow, makeMaskCacheKey, setPrevRef } 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\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 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 applyMaskToRef = (_ref: HTMLElement | null) => {\n if (_ref) applyMaskToElement(_ref, mask, options);\n return _ref;\n };\n maskCache?.set(\n cacheKey,\n flow(applyMaskToRef, ref) as RefCallback<HTMLElement | null>,\n );\n }\n\n const result = {\n ...register,\n ref: maskCache?.get(cacheKey),\n } as UseHookFormMaskReturn<FieldValues>;\n\n setPrevRef(result, ref);\n\n return result;\n}\n"]}
|
|
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","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';\n\nimport type { Input, Mask, Options } 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): ((input: Input | null) => void) {\n const { mask, register, options } = props;\n const ref = useRef<HTMLInputElement | null>(null);\n const maskRef = useRef(mask);\n const optionsRef = useRef(options);\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 return (): void => {\n // server doesn't have dom, so just do nothing\n };\n }\n\n return refCallback;\n}\n","import { useLayoutEffect, useMemo, useRef } from 'react';\n\nimport { applyMaskToElement } from '../core';\nimport { flow, makeMaskCacheKey, setPrevRef } 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\n setPrevRef(result, ref);\n\n return result;\n };\n }, [registerFn]);\n}\n","import { applyMaskToElement } from '../core';\nimport { flow, makeMaskCacheKey, setPrevRef } from '../utils';\n\nimport type { RefCallback } from 'react';\n\nimport type {\n Mask, Options, TanStackFormInputProps, UseTanStackFormMaskReturn,\n} from '../types';\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 const result = {\n ...inputProps,\n ref: ((input: HTMLElement | null) => {\n if (input) applyMaskToElement(input, mask, options);\n }) as RefCallback<HTMLElement | null>,\n } as unknown as UseTanStackFormMaskReturn<T>;\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 applyMaskToRef = (_ref: HTMLElement | null) => {\n if (_ref) applyMaskToElement(_ref, mask, options);\n return _ref;\n };\n\n maskCache?.set(\n cacheKey,\n flow(applyMaskToRef, ref) as RefCallback<HTMLElement | null>,\n );\n }\n\n const result = {\n ...inputProps,\n ref: maskCache?.get(cacheKey),\n } as unknown as UseTanStackFormMaskReturn<T>;\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 { flow, makeMaskCacheKey, setPrevRef } 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\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 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 applyMaskToRef = (_ref: HTMLElement | null) => {\n if (_ref) applyMaskToElement(_ref, mask, options);\n return _ref;\n };\n maskCache?.set(\n cacheKey,\n flow(applyMaskToRef, ref) as RefCallback<HTMLElement | null>,\n );\n }\n\n const result = {\n ...register,\n ref: maskCache?.get(cacheKey),\n } as UseHookFormMaskReturn<FieldValues>;\n\n setPrevRef(result, ref);\n\n return result;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "use-mask-input",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A react Hook for build elegant input masks. Compatible with React Hook Form",
|
|
6
6
|
"author": "Eduardo Borges<euduardoborges@gmail.com>",
|
|
@@ -42,18 +42,18 @@
|
|
|
42
42
|
"@testing-library/dom": "^10.4.1",
|
|
43
43
|
"@testing-library/react": "^16.3.2",
|
|
44
44
|
"@types/inputmask": "5.0.7",
|
|
45
|
-
"@types/node": "25",
|
|
45
|
+
"@types/node": "^25.5.0",
|
|
46
46
|
"@types/react": ">=19",
|
|
47
47
|
"@types/react-dom": ">=19",
|
|
48
|
-
"@vitest/coverage-v8": "4.
|
|
49
|
-
"antd": "^6.3.
|
|
50
|
-
"oxlint": "1.
|
|
48
|
+
"@vitest/coverage-v8": "4.1.1",
|
|
49
|
+
"antd": "^6.3.4",
|
|
50
|
+
"oxlint": "1.57.0",
|
|
51
51
|
"inputmask": "5.0.10-beta.61",
|
|
52
52
|
"jsdom": "^28.1.0",
|
|
53
|
-
"react-hook-form": "7.
|
|
53
|
+
"react-hook-form": "7.72.0",
|
|
54
54
|
"tsup": "8.5.1",
|
|
55
55
|
"typescript": "5.9",
|
|
56
|
-
"vitest": "4.
|
|
56
|
+
"vitest": "4.1.1"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "tsup",
|
package/src/api/index.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { default as useMaskInput } from './useMaskInput';
|
|
2
2
|
export { default as useHookFormMask } from './useHookFormMask';
|
|
3
|
+
export { default as useTanStackFormMask } from './useTanStackFormMask';
|
|
3
4
|
export { default as withMask } from './withMask';
|
|
4
5
|
export { default as withHookFormMask } from './withHookFormMask';
|
|
6
|
+
export { default as withTanStackFormMask } from './withTanStackFormMask';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import withTanStackFormMask from './withTanStackFormMask';
|
|
4
|
+
|
|
5
|
+
import type { Mask, Options, TanStackFormInputProps, UseTanStackFormMaskReturn } from '../types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a helper to mask TanStack Form-compatible input props.
|
|
9
|
+
* Designed for objects returned by field.getInputProps().
|
|
10
|
+
*/
|
|
11
|
+
export default function useTanStackFormMask(): <T extends TanStackFormInputProps>(
|
|
12
|
+
mask: Mask,
|
|
13
|
+
inputProps: T,
|
|
14
|
+
options?: Options,
|
|
15
|
+
) => UseTanStackFormMaskReturn<T> {
|
|
16
|
+
return useMemo(
|
|
17
|
+
() => <T extends TanStackFormInputProps>(
|
|
18
|
+
mask: Mask,
|
|
19
|
+
inputProps: T,
|
|
20
|
+
options?: Options,
|
|
21
|
+
): UseTanStackFormMaskReturn<T> => withTanStackFormMask(inputProps, mask, options),
|
|
22
|
+
[],
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import inputmask from 'inputmask';
|
|
2
|
+
import {
|
|
3
|
+
beforeEach,
|
|
4
|
+
describe, expect, it, vi,
|
|
5
|
+
} from 'vitest';
|
|
6
|
+
|
|
7
|
+
import withTanStackFormMask from './withTanStackFormMask';
|
|
8
|
+
|
|
9
|
+
import type { TanStackFormInputProps } from '../types';
|
|
10
|
+
|
|
11
|
+
vi.mock('inputmask', () => ({
|
|
12
|
+
default: vi.fn((options) => ({
|
|
13
|
+
mask: vi.fn(),
|
|
14
|
+
options,
|
|
15
|
+
})),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
describe('withTanStackFormMask', () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.clearAllMocks();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('returns masked input props with stable structure', () => {
|
|
24
|
+
const inputProps: TanStackFormInputProps = {
|
|
25
|
+
name: 'cpf',
|
|
26
|
+
ref: vi.fn(),
|
|
27
|
+
onBlur: vi.fn(),
|
|
28
|
+
onChange: vi.fn(),
|
|
29
|
+
value: '',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const result = withTanStackFormMask(inputProps, 'cpf');
|
|
33
|
+
|
|
34
|
+
expect(typeof result.ref).toBe('function');
|
|
35
|
+
expect(result.onBlur).toBe(inputProps.onBlur);
|
|
36
|
+
expect(result.onChange).toBe(inputProps.onChange);
|
|
37
|
+
expect(result.name).toBe('cpf');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('applies mask when ref callback receives an input', () => {
|
|
41
|
+
const maskFn = vi.fn();
|
|
42
|
+
vi.mocked(inputmask).mockReturnValue({ mask: maskFn } as any);
|
|
43
|
+
|
|
44
|
+
const input = document.createElement('input');
|
|
45
|
+
const originalRef = vi.fn();
|
|
46
|
+
const inputProps: TanStackFormInputProps = {
|
|
47
|
+
name: 'phone',
|
|
48
|
+
ref: originalRef,
|
|
49
|
+
onBlur: vi.fn(),
|
|
50
|
+
onChange: vi.fn(),
|
|
51
|
+
value: '',
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const result = withTanStackFormMask(inputProps, '(99) 99999-9999');
|
|
55
|
+
result.ref(input);
|
|
56
|
+
|
|
57
|
+
expect(maskFn).toHaveBeenCalled();
|
|
58
|
+
expect(originalRef).toHaveBeenCalledWith(input);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('keeps ref cache stable for same ref and mask', () => {
|
|
62
|
+
const originalRef = vi.fn();
|
|
63
|
+
const inputProps: TanStackFormInputProps = {
|
|
64
|
+
name: 'cpf',
|
|
65
|
+
ref: originalRef,
|
|
66
|
+
onBlur: vi.fn(),
|
|
67
|
+
onChange: vi.fn(),
|
|
68
|
+
value: '',
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const first = withTanStackFormMask(inputProps, 'cpf');
|
|
72
|
+
const second = withTanStackFormMask(inputProps, 'cpf');
|
|
73
|
+
|
|
74
|
+
expect(first.ref).toBe(second.ref);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { applyMaskToElement } from '../core';
|
|
2
|
+
import { flow, makeMaskCacheKey, setPrevRef } from '../utils';
|
|
3
|
+
|
|
4
|
+
import type { RefCallback } from 'react';
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
Mask, Options, TanStackFormInputProps, UseTanStackFormMaskReturn,
|
|
8
|
+
} from '../types';
|
|
9
|
+
|
|
10
|
+
const refCache = new WeakMap<
|
|
11
|
+
RefCallback<HTMLElement | null>,
|
|
12
|
+
Map<string, RefCallback<HTMLElement | null>>
|
|
13
|
+
>();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Enhances TanStack Form-compatible input props with mask support.
|
|
17
|
+
* Works with objects returned by field.getInputProps().
|
|
18
|
+
*/
|
|
19
|
+
export default function withTanStackFormMask<T extends TanStackFormInputProps>(
|
|
20
|
+
inputProps: T,
|
|
21
|
+
mask: Mask,
|
|
22
|
+
options?: Options,
|
|
23
|
+
): UseTanStackFormMaskReturn<T> {
|
|
24
|
+
const { ref } = inputProps;
|
|
25
|
+
|
|
26
|
+
if (!ref) {
|
|
27
|
+
const result = {
|
|
28
|
+
...inputProps,
|
|
29
|
+
ref: ((input: HTMLElement | null) => {
|
|
30
|
+
if (input) applyMaskToElement(input, mask, options);
|
|
31
|
+
}) as RefCallback<HTMLElement | null>,
|
|
32
|
+
} as unknown as UseTanStackFormMaskReturn<T>;
|
|
33
|
+
|
|
34
|
+
setPrevRef(result, ref);
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!refCache.has(ref)) {
|
|
39
|
+
refCache.set(ref, new Map());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const maskCache = refCache.get(ref);
|
|
43
|
+
const cacheKey = makeMaskCacheKey(inputProps.name ?? '', mask);
|
|
44
|
+
|
|
45
|
+
if (!maskCache?.has(cacheKey)) {
|
|
46
|
+
const applyMaskToRef = (_ref: HTMLElement | null) => {
|
|
47
|
+
if (_ref) applyMaskToElement(_ref, mask, options);
|
|
48
|
+
return _ref;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
maskCache?.set(
|
|
52
|
+
cacheKey,
|
|
53
|
+
flow(applyMaskToRef, ref) as RefCallback<HTMLElement | null>,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const result = {
|
|
58
|
+
...inputProps,
|
|
59
|
+
ref: maskCache?.get(cacheKey),
|
|
60
|
+
} as unknown as UseTanStackFormMaskReturn<T>;
|
|
61
|
+
|
|
62
|
+
setPrevRef(result, ref);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
@@ -5,6 +5,12 @@ import {
|
|
|
5
5
|
|
|
6
6
|
import { applyMaskToElement, createMaskInstance } from './maskEngine';
|
|
7
7
|
|
|
8
|
+
type MaskInstance = ReturnType<typeof createMaskInstance>;
|
|
9
|
+
|
|
10
|
+
function stubMaskInstance(maskFn: ReturnType<typeof vi.fn>): MaskInstance {
|
|
11
|
+
return { mask: maskFn } as unknown as MaskInstance;
|
|
12
|
+
}
|
|
13
|
+
|
|
8
14
|
vi.mock('inputmask', () => ({
|
|
9
15
|
default: vi.fn((options) => ({
|
|
10
16
|
mask: vi.fn(),
|
|
@@ -47,7 +53,7 @@ describe('maskEngine', () => {
|
|
|
47
53
|
it('applies mask to input element', () => {
|
|
48
54
|
const input = document.createElement('input');
|
|
49
55
|
const maskFn = vi.fn();
|
|
50
|
-
vi.mocked(inputmask).
|
|
56
|
+
vi.mocked(inputmask).mockImplementation(() => stubMaskInstance(maskFn));
|
|
51
57
|
|
|
52
58
|
applyMaskToElement(input, '999-999');
|
|
53
59
|
|
|
@@ -57,7 +63,7 @@ describe('maskEngine', () => {
|
|
|
57
63
|
it('applies mask to textarea element', () => {
|
|
58
64
|
const textarea = document.createElement('textarea');
|
|
59
65
|
const maskFn = vi.fn();
|
|
60
|
-
vi.mocked(inputmask).
|
|
66
|
+
vi.mocked(inputmask).mockImplementation(() => stubMaskInstance(maskFn));
|
|
61
67
|
|
|
62
68
|
applyMaskToElement(textarea, '999-999');
|
|
63
69
|
|
|
@@ -69,7 +75,7 @@ describe('maskEngine', () => {
|
|
|
69
75
|
const input = document.createElement('input');
|
|
70
76
|
wrapper.appendChild(input);
|
|
71
77
|
const maskFn = vi.fn();
|
|
72
|
-
vi.mocked(inputmask).
|
|
78
|
+
vi.mocked(inputmask).mockImplementation(() => stubMaskInstance(maskFn));
|
|
73
79
|
|
|
74
80
|
applyMaskToElement(wrapper, '999-999');
|
|
75
81
|
|
|
@@ -79,7 +85,7 @@ describe('maskEngine', () => {
|
|
|
79
85
|
it('applies mask to wrapper if no input found inside', () => {
|
|
80
86
|
const wrapper = document.createElement('div');
|
|
81
87
|
const maskFn = vi.fn();
|
|
82
|
-
vi.mocked(inputmask).
|
|
88
|
+
vi.mocked(inputmask).mockImplementation(() => stubMaskInstance(maskFn));
|
|
83
89
|
|
|
84
90
|
applyMaskToElement(wrapper, '999-999');
|
|
85
91
|
|
|
@@ -88,7 +94,7 @@ describe('maskEngine', () => {
|
|
|
88
94
|
|
|
89
95
|
it('does nothing if element is null', () => {
|
|
90
96
|
const maskFn = vi.fn();
|
|
91
|
-
vi.mocked(inputmask).
|
|
97
|
+
vi.mocked(inputmask).mockImplementation(() => stubMaskInstance(maskFn));
|
|
92
98
|
|
|
93
99
|
applyMaskToElement(null as unknown as HTMLElement, '999-999');
|
|
94
100
|
|
|
@@ -98,7 +104,7 @@ describe('maskEngine', () => {
|
|
|
98
104
|
it('applies mask with custom options', () => {
|
|
99
105
|
const input = document.createElement('input');
|
|
100
106
|
const maskFn = vi.fn();
|
|
101
|
-
vi.mocked(inputmask).
|
|
107
|
+
vi.mocked(inputmask).mockImplementation(() => stubMaskInstance(maskFn));
|
|
102
108
|
|
|
103
109
|
applyMaskToElement(input, '999-999', { placeholder: '_' });
|
|
104
110
|
|
package/src/index.tsx
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
export {
|
|
2
2
|
useHookFormMask,
|
|
3
3
|
useMaskInput,
|
|
4
|
+
useTanStackFormMask,
|
|
4
5
|
withHookFormMask,
|
|
5
6
|
withMask,
|
|
7
|
+
withTanStackFormMask,
|
|
6
8
|
} from './api';
|
|
7
9
|
|
|
8
10
|
export type {
|
|
9
11
|
Input,
|
|
10
12
|
Mask,
|
|
11
13
|
Options,
|
|
14
|
+
TanStackFormInputProps,
|
|
15
|
+
UseTanStackFormMaskReturn,
|
|
12
16
|
UseFormRegister,
|
|
13
17
|
UseFormRegisterReturn,
|
|
14
18
|
} from './types';
|
package/src/types/index.ts
CHANGED
|
@@ -36,3 +36,15 @@ export interface UseHookFormMaskReturn<
|
|
|
36
36
|
ref: RefCallback<HTMLElement | null>;
|
|
37
37
|
prevRef: RefCallback<HTMLElement | null>;
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
export interface TanStackFormInputProps {
|
|
41
|
+
name?: string;
|
|
42
|
+
ref?: RefCallback<HTMLElement | null>;
|
|
43
|
+
[key: string]: unknown;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type UseTanStackFormMaskReturn<T extends TanStackFormInputProps = TanStackFormInputProps> =
|
|
47
|
+
Omit<T, 'ref'> & {
|
|
48
|
+
ref: RefCallback<HTMLElement | null>;
|
|
49
|
+
prevRef: RefCallback<HTMLElement | null> | undefined;
|
|
50
|
+
};
|