Skip to content

Commit bf0245b

Browse files
Implement disableParentheses option (GH-16)
2 parents 63a586c + 68c5561 commit bf0245b

15 files changed

+133
-87
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ Apart from the phone-specific properties described below, all [Input](https://mu
8787
| searchNotFound | The value is shown if `enableSearch` is `true` and the query does not match any country. Default value is `No country found`. | string |
8888
| searchPlaceholder | The value is shown if `enableSearch` is `true`. Default value is `Search country`. | string |
8989
| disableDropdown | Disables the manual country selection through the dropdown menu. | boolean |
90+
| disableParentheses | Disables parentheses from the input masks. Default enabled. | boolean |
9091
| onlyCountries | Country codes to be included in the list. E.g. `onlyCountries={['us', 'ca', 'uk']}`. | string[] |
9192
| excludeCountries | Country codes to be excluded from the list of countries. E.g. `excludeCountries={['us', 'ca', 'uk']}`. | string[] |
9293
| preferredCountries | Country codes to be at the top of the list. E.g. `preferredCountries={['us', 'ca', 'uk']}`. | string[] |

examples/base/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"@mui/material": "^5.15.1",
1010
"@types/react": "^18.2.0",
1111
"@types/react-dom": "^18.2.0",
12-
"mui-phone-input": "^0.1.0",
12+
"mui-phone-input": "^0.1.2",
1313
"react": "^18.2.0",
1414
"react-dom": "^18.2.0",
1515
"react-scripts": "^5.0.1",

examples/core/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"@material-ui/core": "^4.12.4",
99
"@types/react": "^17.0.0",
1010
"@types/react-dom": "^17.0.0",
11-
"mui-phone-input": "^0.1.0",
11+
"mui-phone-input": "^0.1.2",
1212
"react": "^17.0.0",
1313
"react-dom": "^17.0.0",
1414
"react-scripts": "^5.0.1",

examples/joy/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"@mui/joy": "^5.0.0-beta.15",
99
"@types/react": "^18.2.0",
1010
"@types/react-dom": "^18.2.0",
11-
"mui-phone-input": "^0.1.0",
11+
"mui-phone-input": "^0.1.2",
1212
"react": "^18.2.0",
1313
"react-dom": "^18.2.0",
1414
"react-scripts": "^5.0.1",

examples/material/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"@types/react": "^18.2.0",
1111
"@types/react-dom": "^18.2.0",
1212
"copy-to-clipboard": "^3.3.3",
13-
"mui-phone-input": "^0.1.0",
13+
"mui-phone-input": "^0.1.2",
1414
"react": "^18.2.0",
1515
"react-dom": "^18.2.0",
1616
"react-hook-form": "^7.51.4",

examples/material/src/Demo.tsx

+12
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const Demo = () => {
2929
const [preview, setPreview] = useState<boolean>(false);
3030
const [dropdown, setDropdown] = useState<boolean>(true);
3131
const [disabled, setDisabled] = useState<boolean>(false);
32+
const [parentheses, setParentheses] = useState(true);
3233

3334
const phoneProps = register("phone", {
3435
validate: (value: any) => checkValidity(parsePhoneNumber(value)),
@@ -129,6 +130,16 @@ const Demo = () => {
129130
style={{margin: 0}}
130131
label="Dropdown"
131132
/>
133+
<FormControlLabel
134+
control={<Switch
135+
defaultChecked
136+
color="primary"
137+
onChange={() => setParentheses(!parentheses)}
138+
/>}
139+
labelPlacement="start"
140+
style={{margin: 0}}
141+
label="Parentheses"
142+
/>
132143
</div>
133144
<Divider textAlign="left" style={{margin: "16px 0"}}>Code</Divider>
134145
<div style={{position: "relative"}}>
@@ -163,6 +174,7 @@ const Demo = () => {
163174
enableSearch={search}
164175
style={{width: "100%"}}
165176
disableDropdown={!dropdown}
177+
disableParentheses={!parentheses}
166178
/>
167179
)}
168180
{(preview && value && !error) && (

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "0.1.1",
2+
"version": "0.1.2",
33
"name": "mui-phone-input",
44
"description": "Advanced, highly customizable phone input component for Material UI.",
55
"keywords": [
@@ -47,7 +47,7 @@
4747
"react": "^16.8.6 || ^17.0.0 || ^18.0.0"
4848
},
4949
"dependencies": {
50-
"react-phone-hooks": "^0.1.4"
50+
"react-phone-hooks": "^0.1.5"
5151
},
5252
"devDependencies": {
5353
"@emotion/styled": "^11.11.0",

src/base/index.tsx

+13-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,17 @@ import {PhoneInputProps, PhoneNumber} from "./types";
1919
injectMergedStyles();
2020

2121
const Input = forwardRef<HTMLInputElement, InputProps>(({slotProps, ...props}, ref) => {
22-
const defaultInputProps = (slotProps?.input as any)?.className ? {} : {outline: "none", border: "none", paddingLeft: 5, width: "calc(100% - 30px)"};
23-
const defaultRootProps = (slotProps?.root as any)?.className ? {} : {background: "white", color: "black", paddingLeft: 5};
22+
const defaultInputProps = (slotProps?.input as any)?.className ? {} : {
23+
outline: "none",
24+
border: "none",
25+
paddingLeft: 5,
26+
width: "calc(100% - 30px)"
27+
};
28+
const defaultRootProps = (slotProps?.root as any)?.className ? {} : {
29+
background: "white",
30+
color: "black",
31+
paddingLeft: 5
32+
};
2433
return (
2534
<BaseInput
2635
ref={ref}
@@ -51,6 +60,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(({slotProps, ...props}, r
5160
const PhoneInput = forwardRef(({
5261
value: initialValue = "",
5362
country = getDefaultISO2Code(),
63+
disableParentheses = false,
5464
onlyCountries = [],
5565
excludeCountries = [],
5666
preferredCountries = [],
@@ -76,6 +86,7 @@ const PhoneInput = forwardRef(({
7686
onlyCountries,
7787
excludeCountries,
7888
preferredCountries,
89+
disableParentheses,
7990
});
8091

8192
const {

src/base/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export interface PhoneInputProps extends Omit<InputProps, "onChange"> {
1111

1212
country?: string;
1313

14+
disableParentheses?: boolean;
15+
1416
onlyCountries?: string[];
1517

1618
excludeCountries?: string[];

src/core/index.tsx

+31-27
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const PhoneInput = forwardRef(({
2929
disabled = false,
3030
enableSearch = false,
3131
disableDropdown = false,
32+
disableParentheses = false,
3233
onlyCountries = [],
3334
excludeCountries = [],
3435
preferredCountries = [],
@@ -150,33 +151,36 @@ const PhoneInput = forwardRef(({
150151
/>
151152
)}
152153
<div className="mui-phone-input-search-list">
153-
{countriesList.length ? countriesList.map(([iso, name, dial, mask]) => (
154-
<MenuItem
155-
disableRipple
156-
key={iso + mask}
157-
value={iso + dial}
158-
style={{maxWidth}}
159-
selected={selectValue === iso + dial}
160-
onClick={() => {
161-
const formattedNumber = getFormattedNumber(mask, mask);
162-
const input = inputRef.current.querySelector("input");
163-
input.value = formattedNumber;
164-
setValue(formattedNumber);
165-
setCountryCode(iso);
166-
setQuery("");
167-
const nativeInputValueSetter = (Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value") as any).set;
168-
nativeInputValueSetter.call(input, formattedNumber);
169-
input.dispatchEvent(new Event("change", {bubbles: true}));
170-
setTimeout(() => input.focus(), 100);
171-
}}
172-
children={<div className="mui-phone-input-select-item">
173-
<div className={`flag ${iso}`}/>
174-
<div className="label">
175-
{name}&nbsp;{displayFormat(mask)}
176-
</div>
177-
</div>}
178-
/>
179-
)) : <MenuItem disabled>{searchNotFound}</MenuItem>}
154+
{countriesList.length ? countriesList.map(([iso, name, dial, pattern]) => {
155+
const mask = disableParentheses ? pattern.replace(/[()]/g, "") : pattern;
156+
return (
157+
<MenuItem
158+
disableRipple
159+
key={iso + mask}
160+
value={iso + dial}
161+
style={{maxWidth}}
162+
selected={selectValue === iso + dial}
163+
onClick={() => {
164+
const formattedNumber = getFormattedNumber(mask, mask);
165+
const input = inputRef.current.querySelector("input");
166+
input.value = formattedNumber;
167+
setValue(formattedNumber);
168+
setCountryCode(iso);
169+
setQuery("");
170+
const nativeInputValueSetter = (Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value") as any).set;
171+
nativeInputValueSetter.call(input, formattedNumber);
172+
input.dispatchEvent(new Event("change", {bubbles: true}));
173+
setTimeout(() => input.focus(), 100);
174+
}}
175+
children={<div className="mui-phone-input-select-item">
176+
<div className={`flag ${iso}`}/>
177+
<div className="label">
178+
{name}&nbsp;{displayFormat(mask)}
179+
</div>
180+
</div>}
181+
/>
182+
)
183+
}) : <MenuItem disabled>{searchNotFound}</MenuItem>}
180184
</div>
181185
</div>
182186
</Select>

src/core/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export interface PhoneInputProps extends Omit<TextFieldProps, "onChange"> {
2121

2222
disableDropdown?: boolean;
2323

24+
disableParentheses?: boolean;
25+
2426
onlyCountries?: string[];
2527

2628
excludeCountries?: string[];

src/index.tsx

+32-27
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const PhoneInput = forwardRef(({
2929
disabled = false,
3030
enableSearch = false,
3131
disableDropdown = false,
32+
disableParentheses = false,
3233
onlyCountries = [],
3334
excludeCountries = [],
3435
preferredCountries = [],
@@ -63,6 +64,7 @@ const PhoneInput = forwardRef(({
6364
onlyCountries,
6465
excludeCountries,
6566
preferredCountries,
67+
disableParentheses,
6668
});
6769

6870
const {
@@ -145,33 +147,36 @@ const PhoneInput = forwardRef(({
145147
/>
146148
)}
147149
<div className="mui-phone-input-search-list">
148-
{countriesList.length ? countriesList.map(([iso, name, dial, mask]) => (
149-
<MenuItem
150-
disableRipple
151-
key={iso + mask}
152-
value={iso + dial}
153-
style={{maxWidth}}
154-
selected={selectValue === iso + dial}
155-
onClick={() => {
156-
const formattedNumber = getFormattedNumber(mask, mask);
157-
const input = inputRef.current.querySelector("input");
158-
input.value = formattedNumber;
159-
setValue(formattedNumber);
160-
setCountryCode(iso);
161-
setQuery("");
162-
const nativeInputValueSetter = (Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value") as any).set;
163-
nativeInputValueSetter.call(input, formattedNumber);
164-
input.dispatchEvent(new Event("change", {bubbles: true}));
165-
setTimeout(() => input.focus(), 100);
166-
}}
167-
children={<div className="mui-phone-input-select-item">
168-
<div className={`flag ${iso}`}/>
169-
<div className="label">
170-
{name}&nbsp;{displayFormat(mask)}
171-
</div>
172-
</div>}
173-
/>
174-
)) : <MenuItem disabled>{searchNotFound}</MenuItem>}
150+
{countriesList.length ? countriesList.map(([iso, name, dial, pattern]) => {
151+
const mask = disableParentheses ? pattern.replace(/[()]/g, "") : pattern;
152+
return (
153+
<MenuItem
154+
disableRipple
155+
key={iso + mask}
156+
value={iso + dial}
157+
style={{maxWidth}}
158+
selected={selectValue === iso + dial}
159+
onClick={() => {
160+
const formattedNumber = getFormattedNumber(mask, mask);
161+
const input = inputRef.current.querySelector("input");
162+
input.value = formattedNumber;
163+
setValue(formattedNumber);
164+
setCountryCode(iso);
165+
setQuery("");
166+
const nativeInputValueSetter = (Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value") as any).set;
167+
nativeInputValueSetter.call(input, formattedNumber);
168+
input.dispatchEvent(new Event("change", {bubbles: true}));
169+
setTimeout(() => input.focus(), 100);
170+
}}
171+
children={<div className="mui-phone-input-select-item">
172+
<div className={`flag ${iso}`}/>
173+
<div className="label">
174+
{name}&nbsp;{displayFormat(mask)}
175+
</div>
176+
</div>}
177+
/>
178+
)
179+
}) : <MenuItem disabled>{searchNotFound}</MenuItem>}
175180
</div>
176181
</div>
177182
</Select>

0 commit comments

Comments
 (0)