import {
useRef,
useEffect,
KeyboardEventHandler,
useCallback,
ReactNode,
useState,
useId,
} from 'react'
import classNames from 'classnames'
import { useSelect } from 'downshift'
import { useTranslation } from 'react-i18next'
import { Form } from 'react-bootstrap'
import FormControl from '@/shared/components/form/form-control'
import MaterialIcon from '@/shared/components/material-icon'
import { CaretUp, CaretDown, Check } from '@phosphor-icons/react'
import { DropdownItem } from '@/shared/components/dropdown/dropdown-menu'
import OLOverlay from '@/shared/components/ol/ol-overlay'
import OLSpinner from './ol/ol-spinner'
import DSFormLabel from '@/shared/components/ds/ds-form-label'
import DSFormGroup from '@/shared/components/ds/ds-form-group'
import DSFormControl from '@/shared/components/ds/ds-form-control'
import { DropdownItemProps } from '@/shared/components/types/dropdown-menu-props'
function SelectMenuPopover({
show,
target,
onHide,
children,
}: {
show: boolean
target: HTMLElement | null
onHide: () => void
children: ReactNode
}) {
const id = useId()
return (
{({ ref, style }) => (
{children}
)}
)
}
export type SelectProps = {
// The items rendered as dropdown options.
items: T[]
// Stringifies an item of type T. The resulting string is rendered as a dropdown option.
itemToString: (item: T | null | undefined) => string
// Caption for the dropdown.
label?: ReactNode
// Attribute used to identify the component inside a Form. This name is used to
// retrieve FormData when the form is submitted. The value of the FormData entry
// is the string returned by `itemToString(selectedItem)`.
name?: string
// Hint text displayed in the initial render.
defaultText?: string
// Initial selected item, displayed in the initial render. When both `defaultText`
// and `defaultItem` are set the latter is ignored.
defaultItem?: T | null
// Stringifies an item. The resulting string is rendered as a subtitle in a dropdown option.
itemToSubtitle?: (item: T | null | undefined) => string
// Stringifies an item. The resulting string is rendered as a React `key` for each item.
itemToKey: (item: T) => string
// Maps an item to a leading icon.
itemToLeadingIcon?: (
item: T | null | undefined
) => DropdownItemProps['leadingIcon']
// Callback invoked after the selected item is updated.
onSelectedItemChanged?: (item: T | null | undefined) => void
// Optionally directly control the selected item.
selected?: T | null
// When `true` item selection is disabled.
disabled?: boolean
// Determine which items should be disabled
itemToDisabled?: (item: T | null | undefined) => boolean
// When `true` displays an "Optional" subtext after the `label` caption.
optionalLabel?: boolean
// When `true` displays a spinner next to the `label` caption.
loading?: boolean
// Show a checkmark next to the selected item
selectedIcon?: boolean
// testId for the input element
dataTestId?: string
// CIAM-specific layout
isCiam?: boolean
size?: React.ComponentProps['size']
// Renders the menu in a portal so it escapes overflow-clipping ancestors.
portal?: boolean
// Optional id for the toggle button element. When provided, enables association
// with an external