{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "phone-input",
  "title": "Phone Input",
  "description": "The Edgecom Phone Input component.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "edgecom-ai/design-system/theme"
  ],
  "files": [
    {
      "path": "src/components/ui/phone-input.tsx",
      "content": "'use client'\n\nimport type { ComponentProps } from 'react'\nimport { createContext, useContext, useMemo, useState } from 'react'\n\nimport * as BasePhoneInput from 'react-phone-number-input'\nimport flags from 'react-phone-number-input/flags'\nimport { Button } from '@/components/ui/button'\nimport {\n  Combobox,\n  ComboboxContent,\n  ComboboxEmpty,\n  ComboboxInput,\n  ComboboxItem,\n  ComboboxList,\n  ComboboxSeparator,\n  ComboboxTrigger,\n  ComboboxValue\n} from '@/components/ui/combobox'\nimport { Input } from '@/components/ui/input'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { cn } from '@/lib/utils'\nimport { EarthIcon } from \"lucide-react\"\n\ntype PhoneInputSize = 'sm' | 'default' | 'lg'\n\nconst PhoneInputContext = createContext<{\n  variant: PhoneInputSize\n  popupClassName?: string\n  scrollAreaClassName?: string\n  inputClassName?: string\n  triggerClassName?: string\n  readOnly?: boolean\n}>({\n  variant: 'default',\n  popupClassName: undefined,\n  scrollAreaClassName: undefined,\n  inputClassName: undefined,\n  triggerClassName: undefined,\n  readOnly: false\n})\n\ntype PhoneInputProps = Omit<ComponentProps<'input'>, 'onChange' | 'value' | 'ref'> &\n  Omit<\n    BasePhoneInput.Props<typeof BasePhoneInput.default>,\n    'onChange' | 'variant' | 'popupClassName' | 'scrollAreaClassName'\n  > & {\n    onChange?: (value: BasePhoneInput.Value) => void\n    variant?: PhoneInputSize\n    popupClassName?: string\n    scrollAreaClassName?: string\n    inputClassName?: string\n    triggerClassName?: string\n  }\n\nconst PhoneInput = ({\n  className,\n  variant,\n  popupClassName,\n  scrollAreaClassName,\n  inputClassName,\n  triggerClassName,\n  onChange,\n  value,\n  ...props\n}: PhoneInputProps) => {\n  const phoneInputSize = variant || 'default'\n\n  return (\n    <PhoneInputContext.Provider\n      value={{\n        variant: phoneInputSize,\n        popupClassName,\n        scrollAreaClassName,\n        inputClassName,\n        triggerClassName,\n        readOnly: props.readOnly\n      }}\n    >\n      <BasePhoneInput.default\n        className={cn(\n          'flex',\n          props['aria-invalid'] &&\n            '[&_*[data-slot=combobox-trigger]]:border-destructive [&_*[data-slot=combobox-trigger]]:ring-destructive/50',\n          className\n        )}\n        flagComponent={FlagComponent}\n        countrySelectComponent={CountrySelect}\n        inputComponent={InputComponent}\n        smartCaret={false}\n        value={value || undefined}\n        onChange={value => onChange?.(value || ('' as BasePhoneInput.Value))}\n        {...props}\n      />\n    </PhoneInputContext.Provider>\n  )\n}\n\nconst InputComponent = ({ className, ...props }: ComponentProps<typeof Input>) => {\n  const { variant, inputClassName } = useContext(PhoneInputContext)\n\n  return (\n    <Input\n      className={cn(\n        'rounded-l-none focus:z-1',\n        variant === 'sm' && 'h-auto! py-0!',\n        variant === 'lg' && 'h-auto!',\n        inputClassName,\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\ntype CountryEntry = { label: string; value: BasePhoneInput.Country | undefined }\n\ntype CountrySelectProps = {\n  disabled?: boolean\n  value: BasePhoneInput.Country\n  options: CountryEntry[]\n  onChange: (country: BasePhoneInput.Country) => void\n}\n\nconst CountrySelect = ({ disabled, value: selectedCountry, options: countryList, onChange }: CountrySelectProps) => {\n  const { variant, popupClassName, triggerClassName, readOnly } = useContext(PhoneInputContext)\n  const [searchValue, setSearchValue] = useState('')\n\n  const filteredCountries = useMemo(() => {\n    if (!searchValue) return countryList\n\n    return countryList.filter(({ label }) => label.toLowerCase().includes(searchValue.toLowerCase()))\n  }, [countryList, searchValue])\n\n  return (\n    <Combobox\n      items={filteredCountries}\n      value={selectedCountry || ''}\n      onValueChange={(country: BasePhoneInput.Country | null) => {\n        if (country) {\n          onChange(country)\n        }\n      }}\n    >\n      <ComboboxTrigger\n        render={\n          <Button\n            variant='outline'\n            size={variant}\n            className={cn(\n              'flex gap-1 rounded-r-none border-e-0 px-2.5 py-0 leading-none hover:bg-transparent focus:z-10 aria-pressed:bg-transparent',\n              disabled && 'dark:disabled:bg-input/80',\n              triggerClassName\n            )}\n            disabled={disabled || readOnly}\n          >\n            <span className='sr-only'>\n              <ComboboxValue />\n            </span>\n            <FlagComponent country={selectedCountry} countryName={selectedCountry} />\n          </Button>\n        }\n      />\n      <ComboboxContent className={cn('w-xs *:data-[slot=input-group]:bg-transparent', popupClassName)}>\n        <ComboboxInput\n          placeholder='e.g. United States'\n          value={searchValue}\n          onChange={e => setSearchValue(e.target.value)}\n          showTrigger={false}\n          className='border-input focus-visible:border-border rounded-none border-0 px-0 py-2.5 shadow-none ring-0! outline-none! focus-visible:ring-0 focus-visible:ring-offset-0'\n        />\n        <ComboboxSeparator />\n        <ComboboxEmpty className='px-4 py-2.5 text-sm'>No country found.</ComboboxEmpty>\n        <ComboboxList>\n          <div className='relative flex max-h-full'>\n            <div className='flex max-h-[min(var(--available-height),24rem)] w-full scroll-pt-2 scroll-pb-2 flex-col overscroll-contain'>\n              <ScrollArea className='size-full min-h-0 **:data-[slot=scroll-area-scrollbar]:m-0 [&_[data-slot=scroll-area-viewport]]:h-full [&_[data-slot=scroll-area-viewport]]:overscroll-contain'>\n                {filteredCountries.map((item: CountryEntry) =>\n                  item.value ? (\n                    <ComboboxItem key={item.value} value={item.value} className='flex items-center gap-2'>\n                      <FlagComponent country={item.value} countryName={item.label} />\n                      <span className='flex-1 text-sm'>{item.label}</span>\n                      <span className='text-foreground/50 text-sm'>\n                        {`+${BasePhoneInput.getCountryCallingCode(item.value)}`}\n                      </span>\n                    </ComboboxItem>\n                  ) : null\n                )}\n              </ScrollArea>\n            </div>\n          </div>\n        </ComboboxList>\n      </ComboboxContent>\n    </Combobox>\n  )\n}\n\nconst FlagComponent = ({ country, countryName }: BasePhoneInput.FlagProps) => {\n  const Flag = flags[country]\n\n  return (\n    <span className=\"flex h-4 w-4 items-center justify-center [&_svg:not([class*='size-'])]:size-full! [&_svg:not([class*='size-'])]:rounded-[5px]\">\n      {Flag ? (\n        <Flag title={countryName} />\n      ) : (\n        <EarthIcon className='size-4 opacity-60' />\n      )}\n    </span>\n  )\n}\n\nexport { PhoneInput }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}