Files
web/components/TempDesignSystem/Form/Country/index.tsx
2024-04-16 09:24:31 +02:00

110 lines
2.9 KiB
TypeScript

"use client"
import { useController, useFormContext } from "react-hook-form"
import { useEffect, useRef, useState } from "react"
import { _ } from "@/lib/translation"
import { countries } from "./countries"
import {
Button,
ComboBox,
FieldError,
Input,
ListBox,
ListBoxItem,
Popover,
type Key,
} from "react-aria-components"
import { ErrorMessage } from "@hookform/error-message"
import SelectChevron from "../SelectChevron"
import styles from "./country.module.css"
import type { CountryProps } from "./country"
export default function CountrySelect({
name = "country",
placeholder = "Select a country",
registerOptions,
}: CountryProps) {
const divRef = useRef<HTMLDivElement>(null)
const [divElement, setDivElement] = useState(divRef.current)
const { control, setValue } = useFormContext()
const { field } = useController({
control,
name,
rules: registerOptions,
})
const [selectedKey, setSelectedKey] = useState(() => {
if (field.value) {
const selected = countries.find(
(country) =>
country.name === field.value || country.code === field.value
)
if (selected) {
return selected.name
}
}
return ""
})
function handleChange(country: Key) {
setSelectedKey(String(country))
setValue(name, country)
}
useEffect(() => {
if (divRef.current) {
setDivElement(divRef.current)
}
}, [divRef.current])
return (
<div className={styles.container} ref={divRef}>
<ComboBox
className={styles.select}
isRequired={!!registerOptions?.required}
name={field.name}
onBlur={field.onBlur}
onSelectionChange={handleChange}
ref={field.ref}
selectedKey={selectedKey}
>
<div className={styles.comboBoxContainer}>
<Input className={styles.input} placeholder={_(placeholder)} />
<Button className={styles.button}>
<SelectChevron />
</Button>
</div>
<FieldError>
<ErrorMessage name={name} />
</FieldError>
<Popover
className={styles.popover}
placement="bottom"
shouldFlip={false}
/**
* react-aria uses portals to render Popover in body
* unless otherwise specified. We need it to be contained
* by this component to both access css variables assigned
* on the container as well as to not overflow it at any time.
*/
UNSTABLE_portalContainer={divElement ?? undefined}
>
<ListBox>
{countries.map((country, idx) => (
<ListBoxItem
className={styles.listBoxItem}
id={country.name}
key={`${country.code}-${idx}`}
>
{country.name}
</ListBoxItem>
))}
</ListBox>
</Popover>
</ComboBox>
</div>
)
}