0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-24 22:41:28 -05:00
logto/packages/ui/src/components/Input/PhoneInput.tsx
simeng-li 86030ab97c
feat(ui): implement phonenumber input field ()
* feat(ui): implement phonenumber input field

implement phonenumber input field

* fix(ui): phone input ui fix

phone input ui fix

* fix(ui): should not show error if not interacted

should not show error if not interacted

* fix(ui): fix styling

fix styling

* feat(ui): add typeMode for phone input

add typeMode for phone input

* chore(ui): update pnpm-lock

update pnpm-lock
2022-03-15 17:31:13 +08:00

111 lines
2.9 KiB
TypeScript

import classNames from 'classnames';
import React, { useState, useMemo, useRef } from 'react';
import { CountryCallingCode, CountryMetaData } from '@/hooks/use-phone-number';
import { ClearIcon, DownArrowIcon } from '../Icons';
import * as styles from './index.module.scss';
import * as phoneInputStyles from './phoneInput.module.scss';
export type Props = {
name: string;
autoComplete?: AutoCompleteType;
isDisabled?: boolean;
className?: string;
placeholder?: string;
countryCallingCode?: CountryCallingCode;
nationalNumber: string;
countryList?: CountryMetaData[];
hasError?: boolean;
onChange: (value: { countryCallingCode?: CountryCallingCode; nationalNumber?: string }) => void;
};
const PhoneInput = ({
name,
autoComplete,
isDisabled,
className,
placeholder,
countryCallingCode,
nationalNumber,
countryList,
hasError = false,
onChange,
}: Props) => {
const [onFocus, setOnFocus] = useState(false);
const inputReference = useRef<HTMLInputElement>(null);
const countrySelector = useMemo(() => {
if (!countryCallingCode || !countryList) {
return null;
}
return (
<div className={phoneInputStyles.countryCodeSelector}>
<span>{`+${countryCallingCode}`}</span>
<DownArrowIcon />
<select
onChange={({ target: { value } }) => {
onChange({ countryCallingCode: value });
// Auto Focus to the input
if (inputReference.current) {
inputReference.current.focus();
const { length } = inputReference.current.value;
inputReference.current.setSelectionRange(length, length);
}
}}
>
{countryList.map(({ countryCode, countryCallingCode, countryName }) => (
<option key={countryCode} value={countryCallingCode}>
{`${countryName ?? countryCode}: +${countryCallingCode}`}
</option>
))}
</select>
</div>
);
}, [countryCallingCode, countryList, onChange]);
return (
<div
className={classNames(
styles.wrapper,
onFocus && styles.focus,
hasError && styles.error,
className
)}
>
{countrySelector}
<input
ref={inputReference}
name={name}
disabled={isDisabled}
placeholder={placeholder}
value={nationalNumber}
type="tel"
inputMode="numeric"
autoComplete={autoComplete}
onFocus={() => {
setOnFocus(true);
}}
onBlur={() => {
setOnFocus(false);
}}
onChange={({ target: { value } }) => {
onChange({ nationalNumber: value });
}}
/>
{nationalNumber && onFocus && (
<ClearIcon
className={styles.actionButton}
onMouseDown={(event) => {
event.preventDefault();
onChange({ nationalNumber: '' });
}}
/>
)}
</div>
);
};
export default PhoneInput;