Skip to content

Commit c7c8f8e

Browse files
Merge pull request #8225 from primefaces/v11-usemask
New useMask hook
2 parents 48b0d9b + 1cc7536 commit c7c8f8e

8 files changed

Lines changed: 855 additions & 0 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useMask, type UseMaskChangeEvent } from '@primereact/hooks';
2+
import { InputTextInstance } from '@primereact/types/shared/inputtext';
3+
import { InputText } from 'primereact/inputtext';
4+
import * as React from 'react';
5+
6+
export default function BasicDemo() {
7+
const [value, setValue] = React.useState('');
8+
const ref = React.useRef<InputTextInstance>(null);
9+
const [target, setTarget] = React.useState<HTMLInputElement | null>(null);
10+
11+
React.useEffect(() => {
12+
if (ref.current?.elementRef?.current) {
13+
setTarget(ref.current.elementRef.current as HTMLInputElement);
14+
}
15+
}, []);
16+
17+
const { onMaskInput, onMaskKeyDown, onMaskKeyPress, onMaskFocus, onMaskBlur, onMaskPaste } = useMask({
18+
mask: '99-999999',
19+
onMaskChange: (event: UseMaskChangeEvent) => setValue(event.value ?? ''),
20+
target: target as HTMLInputElement
21+
});
22+
23+
return (
24+
<div className="card flex justify-center">
25+
<InputText ref={ref} value={value} placeholder="99-999999" onInput={onMaskInput} onKeyDown={onMaskKeyDown} onKeyPress={onMaskKeyPress} onFocus={onMaskFocus} onBlur={onMaskBlur} onPaste={onMaskPaste} />
26+
</div>
27+
);
28+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { useMask, type UseMaskChangeEvent } from '@primereact/hooks';
2+
import { InputTextInstance } from '@primereact/types/shared/inputtext';
3+
import { InputText } from 'primereact/inputtext';
4+
import { Label } from 'primereact/label';
5+
import * as React from 'react';
6+
7+
export default function FormatPatternsDemo() {
8+
const [value1, setValue1] = React.useState('');
9+
const [value2, setValue2] = React.useState('');
10+
const [value3, setValue3] = React.useState('');
11+
const input1 = React.useRef<InputTextInstance>(null);
12+
const input2 = React.useRef<InputTextInstance>(null);
13+
const input3 = React.useRef<InputTextInstance>(null);
14+
const [target1, setTarget1] = React.useState<HTMLInputElement | null>(null);
15+
const [target2, setTarget2] = React.useState<HTMLInputElement | null>(null);
16+
const [target3, setTarget3] = React.useState<HTMLInputElement | null>(null);
17+
18+
React.useEffect(() => {
19+
if (input1.current?.elementRef?.current) {
20+
setTarget1(input1.current.elementRef.current as HTMLInputElement);
21+
}
22+
23+
if (input2.current?.elementRef?.current) {
24+
setTarget2(input2.current.elementRef.current as HTMLInputElement);
25+
}
26+
27+
if (input3.current?.elementRef?.current) {
28+
setTarget3(input3.current.elementRef.current as HTMLInputElement);
29+
}
30+
}, []);
31+
32+
// SSN Mask
33+
const {
34+
onMaskInput: onMaskInput1,
35+
onMaskKeyDown: onMaskKeyDown1,
36+
onMaskKeyPress: onMaskKeyPress1,
37+
onMaskFocus: onMaskFocus1,
38+
onMaskBlur: onMaskBlur1,
39+
onMaskPaste: onMaskPaste1
40+
} = useMask({
41+
mask: '999-99-9999',
42+
onMaskChange: (event: UseMaskChangeEvent) => setValue1(event.value ?? ''),
43+
target: target1 as HTMLInputElement
44+
});
45+
46+
// Phone Mask
47+
const {
48+
onMaskInput: onMaskInput2,
49+
onMaskKeyDown: onMaskKeyDown2,
50+
onMaskKeyPress: onMaskKeyPress2,
51+
onMaskFocus: onMaskFocus2,
52+
onMaskBlur: onMaskBlur2,
53+
onMaskPaste: onMaskPaste2
54+
} = useMask({
55+
mask: '(999) 999-9999',
56+
onMaskChange: (event: UseMaskChangeEvent) => setValue2(event.value ?? ''),
57+
target: target2 as HTMLInputElement
58+
});
59+
60+
// Serial Mask
61+
const {
62+
onMaskInput: onMaskInput3,
63+
onMaskKeyDown: onMaskKeyDown3,
64+
onMaskKeyPress: onMaskKeyPress3,
65+
onMaskFocus: onMaskFocus3,
66+
onMaskBlur: onMaskBlur3,
67+
onMaskPaste: onMaskPaste3
68+
} = useMask({
69+
mask: 'a*-999-a999',
70+
onMaskChange: (event: UseMaskChangeEvent) => setValue3(event.value ?? ''),
71+
target: target3 as HTMLInputElement
72+
});
73+
74+
return (
75+
<div className="card flex flex-wrap gap-4">
76+
<div className="flex-auto">
77+
<Label htmlFor="ssn" className="font-bold block mb-2">
78+
SSN
79+
</Label>
80+
<InputText ref={input1} value={value1} id="ssn" placeholder="999-99-9999" fluid onInput={onMaskInput1} onKeyDown={onMaskKeyDown1} onKeyPress={onMaskKeyPress1} onFocus={onMaskFocus1} onBlur={onMaskBlur1} onPaste={onMaskPaste1} />
81+
</div>
82+
83+
<div className="flex-auto">
84+
<Label htmlFor="phone" className="font-bold block mb-2">
85+
Phone
86+
</Label>
87+
<InputText ref={input2} value={value2} id="phone" placeholder="(999) 999-9999" fluid onInput={onMaskInput2} onKeyDown={onMaskKeyDown2} onKeyPress={onMaskKeyPress2} onFocus={onMaskFocus2} onBlur={onMaskBlur2} onPaste={onMaskPaste2} />
88+
</div>
89+
90+
<div className="flex-auto">
91+
<Label htmlFor="serial" className="font-bold block mb-2">
92+
Serial
93+
</Label>
94+
<InputText ref={input3} value={value3} id="serial" placeholder="a*-999-a999" fluid onInput={onMaskInput3} onKeyDown={onMaskKeyDown3} onKeyPress={onMaskKeyPress3} onFocus={onMaskFocus3} onBlur={onMaskBlur3} onPaste={onMaskPaste3} />
95+
</div>
96+
</div>
97+
);
98+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useMask, type UseMaskChangeEvent } from '@primereact/hooks';
2+
import { InputTextInstance } from '@primereact/types/shared/inputtext';
3+
import { InputText } from 'primereact/inputtext';
4+
import * as React from 'react';
5+
6+
export default function OptionalDemo() {
7+
const [value, setValue] = React.useState('');
8+
const ref = React.useRef<InputTextInstance>(null);
9+
const [target, setTarget] = React.useState<HTMLInputElement | null>(null);
10+
11+
React.useEffect(() => {
12+
if (ref.current?.elementRef?.current) {
13+
setTarget(ref.current.elementRef.current as HTMLInputElement);
14+
}
15+
}, []);
16+
17+
const { onMaskInput, onMaskKeyDown, onMaskKeyPress, onMaskFocus, onMaskBlur, onMaskPaste } = useMask({
18+
mask: '(999) 999-9999? x99999',
19+
onMaskChange: (event: UseMaskChangeEvent) => setValue(event.value ?? ''),
20+
target: target as HTMLInputElement
21+
});
22+
23+
return (
24+
<div className="card flex justify-center">
25+
<InputText ref={ref} placeholder="(999) 999-9999 x99999" value={value} onInput={onMaskInput} onKeyDown={onMaskKeyDown} onKeyPress={onMaskKeyPress} onFocus={onMaskFocus} onBlur={onMaskBlur} onPaste={onMaskPaste} />
26+
</div>
27+
);
28+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { useMask, type UseMaskChangeEvent } from '@primereact/hooks';
2+
import * as React from 'react';
3+
4+
export default function SlotCharDemo() {
5+
const [value, setValue] = React.useState('');
6+
const ref = React.useRef<HTMLInputElement>(null);
7+
const [target, setTarget] = React.useState<HTMLInputElement | null>(null);
8+
9+
React.useEffect(() => {
10+
if (ref.current) {
11+
setTarget(ref.current as HTMLInputElement);
12+
}
13+
}, []);
14+
15+
const { onMaskInput, onMaskKeyDown, onMaskKeyPress, onMaskFocus, onMaskBlur, onMaskPaste } = useMask({
16+
mask: '99/99/9999',
17+
slotChar: 'mm/dd/yyyy',
18+
onMaskChange: (event: UseMaskChangeEvent) => setValue(event.value ?? ''),
19+
target: target as HTMLInputElement
20+
});
21+
22+
return (
23+
<div className="card flex justify-center">
24+
<input
25+
type="text"
26+
ref={ref}
27+
placeholder="mm/dd/yyyy"
28+
value={value}
29+
onInput={onMaskInput}
30+
onKeyDown={onMaskKeyDown}
31+
onKeyPress={onMaskKeyPress}
32+
onFocus={onMaskFocus}
33+
onBlur={onMaskBlur}
34+
onPaste={onMaskPaste}
35+
className="border border-gray-300 rounded-md px-3 py-1"
36+
/>
37+
</div>
38+
);
39+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
title: useMask
3+
description: useMask is used to enter input in a certain format such as numeric, date, currency, email and phone.
4+
---
5+
6+
## Usage
7+
8+
```tsx
9+
import { useMask } from '@primereact/hooks';
10+
```
11+
12+
```tsx
13+
const mask = useMask();
14+
```
15+
16+
## Examples
17+
18+
### Basic
19+
20+
<DocDemoViewer name="usemask:basic-demo" />
21+
22+
### Format Patterns
23+
24+
Mask format can be a combination of the following definitions; _a_ for alphabetic characters, _9_ for numeric characters and _\*_ for alphanumberic characters. In addition, formatting characters like _(_ , _)_ , _-_ are also accepted.
25+
26+
<DocDemoViewer name="usemask:format-patterns-demo" />
27+
28+
### Optional
29+
30+
When the input does not complete the mask definition, it is cleared by default. Use _autoClear_ option to control this behavior. In addition, _?_ is used to mark anything after the question mark optional.
31+
32+
<DocDemoViewer name="usemask:optional-demo" />
33+
34+
### Slot Character
35+
36+
Default placeholder for a mask is underscore that can be customized using _slotChar_ option.
37+
38+
<DocDemoViewer name="usemask:slot-char-demo" />

packages/hooks/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from './use-controlled-state';
33
export * from './use-event-listener';
44
export * from './use-id';
55
export * from './use-key-filter';
6+
export * from './use-mask';
67
export * from './use-match-media';
78
export * from './use-mount-effect';
89
export * from './use-previous';

packages/hooks/src/use-mask/index.test.ts

Whitespace-only changes.

0 commit comments

Comments
 (0)