@nish1896/rhf-mui-components
Version:
A suite of 20+ reusable Material UI components for React Hook Form to minimize your time and effort in creating and styling forms
111 lines (110 loc) • 7.17 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
* Code Reference -
* https://react-international-phone.vercel.app/docs/Advanced%20Usage/useWithUiLibs
*/
import { useContext } from 'react';
import { Controller } from 'react-hook-form';
import TextField from '@mui/material/TextField';
import InputAdornment from '@mui/material/InputAdornment';
import Divider from '@mui/material/Divider';
import Select from '@mui/material/Select';
import MenuItem from '@mui/material/MenuItem';
import Typography from '@mui/material/Typography';
import { defaultCountries, FlagImage, parseCountry, usePhoneInput } from 'react-international-phone';
import { RHFMuiConfigContext } from '../../config/ConfigProvider';
import { FormControl, FormLabel, FormLabelText, FormHelperText } from '../../mui/common';
import { fieldNameToLabel, keepLabelAboveFormField, isAboveMuiV5 } from '../../utils';
import 'react-international-phone/style.css';
const RHFPhoneInput = ({ fieldName, control, registerOptions, required, value, onValueChange, label, showLabelAboveFormField, formLabelProps, helperText, errorMessage, hideErrorMessage, formHelperTextProps, disabled, phoneInputProps, slotProps, ...rest }) => {
const { allLabelsAboveFields } = useContext(RHFMuiConfigContext);
const isError = Boolean(errorMessage);
const fieldLabel = label ?? fieldNameToLabel(fieldName);
const isLabelAboveFormField = keepLabelAboveFormField(showLabelAboveFormField, allLabelsAboveFields);
const { countries, hideDropdown, preferredCountries, forceDialCode, ...otherPhoneInputProps } = phoneInputProps ?? {};
const countryOptions = countries ?? defaultCountries;
let countriesToList = countryOptions;
let countriesToListAtTop = [];
/**
* Render preferred countries at the top of the list.
* Preferred countries will maintain the order in which they were
* specified in the props, while other countries will be sorted
* alphabetically.
*/
if (preferredCountries?.length) {
countriesToListAtTop = countryOptions.filter(country => preferredCountries.includes(parseCountry(country).iso2));
countriesToListAtTop.sort((a, b) => {
return (preferredCountries.indexOf(parseCountry(a).iso2)
- preferredCountries.indexOf(parseCountry(b).iso2));
});
countriesToList = countryOptions.filter(country => !preferredCountries.includes(parseCountry(country).iso2));
}
const { inputValue, handlePhoneValueChange, inputRef, country, setCountry } = usePhoneInput({
...otherPhoneInputProps,
value,
onChange: (phoneData) => {
if (onValueChange) {
onValueChange(phoneData);
}
},
countries: countryOptions,
preferredCountries,
forceDialCode: hideDropdown ?? forceDialCode
});
return (_jsxs(FormControl, { error: isError, children: [_jsx(FormLabel, { label: fieldLabel, isVisible: isLabelAboveFormField, required: required, error: isError, formLabelProps: formLabelProps }), _jsx(Controller, { name: fieldName, control: control, rules: registerOptions, defaultValue: inputValue, render: ({ field }) => {
const startAdornment = (_jsx(InputAdornment, { position: "start", style: { marginRight: '2px', marginLeft: '-8px' }, children: _jsxs(Select, { MenuProps: {
style: {
height: '300px',
width: '360px',
top: '10px',
left: '-34px'
},
transformOrigin: {
vertical: 'top',
horizontal: 'left'
}
}, sx: {
width: 'max-content',
fieldset: {
display: 'none'
},
'&.Mui-focused:has(div[aria-expanded="false"])': {
fieldset: {
display: 'block'
}
},
'.MuiSelect-select': {
padding: '8px',
paddingRight: '24px !important'
},
svg: {
right: 0
}
}, value: country.iso2, disabled: disabled || hideDropdown, onChange: e => {
setCountry(e.target.value);
}, renderValue: value => (_jsx(FlagImage, { iso2: value, style: { display: 'flex' } })), children: [countriesToListAtTop.map(c => {
const countryInfo = parseCountry(c);
return (_jsxs(MenuItem, { value: countryInfo.iso2, children: [_jsx(FlagImage, { iso2: countryInfo.iso2, style: { marginRight: '8px' } }), _jsx(Typography, { marginRight: "8px", children: countryInfo.name }), _jsxs(Typography, { color: "gray", children: ["+", countryInfo.dialCode] })] }, countryInfo.iso2));
}), countriesToListAtTop.length > 0 && _jsx(Divider, {}), countriesToList.map(c => {
const countryInfo = parseCountry(c);
return (_jsxs(MenuItem, { value: countryInfo.iso2, children: [_jsx(FlagImage, { iso2: countryInfo.iso2, style: { marginRight: '8px' } }), _jsx(Typography, { marginRight: "8px", children: countryInfo.name }), _jsxs(Typography, { color: "gray", children: ["+", countryInfo.dialCode] })] }, countryInfo.iso2));
})] }) }));
return (_jsx(TextField, { ...field, ...rest, value: inputValue, autoComplete: fieldName, type: "tel", onChange: e => {
handlePhoneValueChange(e);
field.onChange(e.target.value);
}, inputRef: ref => {
field.ref(ref);
inputRef.current = ref;
}, label: !isLabelAboveFormField
? _jsx(FormLabelText, { label: fieldLabel, required: required })
: undefined, error: isError, disabled: disabled, ...(isAboveMuiV5
? {
slotProps: {
...slotProps,
input: { startAdornment }
}
}
: { InputProps: { startAdornment } }) }));
} }), _jsx(FormHelperText, { error: isError, errorMessage: errorMessage, hideErrorMessage: hideErrorMessage, helperText: helperText, formHelperTextProps: formHelperTextProps })] }));
};
export default RHFPhoneInput;