import { zodResolver } from '@hookform/resolvers/zod'; import clsx from 'clsx'; import { AnimatePresence, motion } from 'framer-motion'; import React, { HTMLProps, useCallback, useState } from 'react'; import { Control, useForm } from 'react-hook-form'; import { animated, useSpring } from 'react-spring'; import { z } from 'zod'; import { CountryFlag } from '../src/country-flag/country-flag'; import { PhoneInput, usePhone } from '../src/phone-input/phone-input'; import { phoneValidationSchema, usePhoneState, } from '../src/use-phone-state/use-phone-state'; import Modal from './base/modal'; import styles from './phone-input-stories.module.scss'; export default { component: PhoneInput, parameters: { layout: 'centered', }, tags: ['autodocs'], title: 'PhoneInput', }; const schema = z.object({ name: z.string().min(1, 'Name is required').max(255, 'Name is too long'), phone: phoneValidationSchema(), }); type FormPhoneInputProps = { control: Control; name: string; onChange?: (e: React.ChangeEvent) => void; } & HTMLProps; function FormPhoneInputWithForm(props: FormPhoneInputProps) { const { control, name } = props; const initialCountry = 'US'; const [search, setSearch] = useState(''); return ( {({ country, countryList }) => ( <> { setSearch(''); }} > <> setSearch(e.target.value)} placeholder="Search" value={search} />
    {countryList .filter((item) => item.name.toLowerCase().includes(search.toLowerCase()) ) .map((item) => ( {item.name} ))}
)}
); } export function AnimatedReactSpringDialog() { return ( {({ country }) => ( )} {({ countryList, open }) => { const spring = useSpring({ from: { opacity: 0, transform: 'translateY(-20px)' }, to: { opacity: open ? 1 : 0, pointerEvents: open ? 'all' : 'none', transform: open ? 'translateY(0)' : 'translateY(-20px)', }, }); return (
    {countryList.map((countryItem) => ( {countryItem.name} ))}
); }}
); } export function AnimatedFramerMotionDialog() { return ( {({ country }) => ( )} {({ countryList, open }) => ( {open && (
    {countryList.map((countryItem) => ( {countryItem.name} ))}
)}
)}
); } export function ReactHookFormAndZod() { const defaultValues = { name: '', phone: '+1', }; const { control, formState: { errors }, handleSubmit, register, reset, } = useForm>({ defaultValues, resolver: zodResolver(schema), }); const [submitState, setSubmitState] = useState>(defaultValues); return (
{ setSubmitState(data); reset(); })} > {errors.name && {errors.name.message}} {errors.phone && {errors.phone.message}}

Submit state

{JSON.stringify(submitState, null, 2)}
); } export function Styled() { const [search, setSearch] = useState(''); const [isValid, setIsValid] = useState(false); const [country, setCountry] = useState('US'); const [phone, setPhone] = useState(''); const [focused, setFocused] = useState(false); return (
{ e.preventDefault(); }} > {({ countryList }) => ( <>
setSearch(e.target.value)} placeholder="Search" type="text" value={search} />
    {countryList .filter((countryItem) => countryItem.name .toLowerCase() .includes(search.toLowerCase()) ) .map((countryItem) => ( {countryItem.name} ))}
{ setFocused(false); }} onChange={(e) => { setPhone(e.target.value); }} onFocus={(e) => { setFocused(true); }} type="tel" value={phone} />
)}
); } export function StyledWithAnimation() { const { country, countryList, handleCountryChange, handlePhoneNumberChange, isValid, phoneNumber, } = usePhoneState(); const [search, setSearch] = useState(''); const pickCountry = useCallback( (e: React.KeyboardEvent | React.MouseEvent) => { setSearch(''); const target = e.currentTarget as HTMLLIElement; handleCountryChange(target.dataset.value as unknown as string); }, [] ); const searchCountryList = countryList.filter((countryItem) => countryItem.name.toLowerCase().includes(search.toLowerCase()) ); return (
{ e.preventDefault(); }} >
); } export function Hook() { const state = usePhoneState(); const [isOpen, setIsOpen] = useState(false); const { getListItemProps, numberInputProps, phoneInputDialogProps, triggerProps, } = usePhone( { isDialogOpen: isOpen, }, state ); return (
{ e.preventDefault(); }} >
{state.countryList.map((countryItem) => (
  • { state.handleCountryChange(countryItem.alpha2); setIsOpen(false); }} onKeyDown={(e) => { if (e.key === 'Enter') { state.handleCountryChange(countryItem.alpha2); setIsOpen(false); } }} > {countryItem.name}
  • ))}
    { state.handlePhoneNumberChange(e.target.value); }} placeholder="Phone" value={state.phoneNumber} />
    {state.isValid ? 'Valid' : 'Invalid'} {`${state.country}: ${state.phoneNumber}`}
    ); } export function BasicWithCountryFlag() { return ( {({ country }) => ( )} {({ countryList }) => (
      {countryList.map((countryItem) => ( {countryItem.name} ))}
    )} {({ phone }) => ( )}
    ); } export function Basic() { return ( ); } export function Portal() { return ( {({ country }) => ( )} {({ countryList }) => (
      {countryList.map((countryItem) => ( {countryItem.name} ))}
    )}
    ); } export function ModalPortal() { return (
    {({ country }) => ( )} {({ countryList }) => (
      {countryList.map((countryItem) => ( {countryItem.name} ))}
    )}
    ); } export function Flags() { const { country, countryList, handleCountryChange } = usePhoneState(); return (
    {countryList.map((countryItem) => (
    {`${countryItem.name} (${countryItem.alpha2})`}
    IMG
    SVG
    ))}
    ); }