import type { ForwardedRef } from 'react'; import React, { useId, useMemo } from 'react'; import { type AriaButtonProps } from 'react-aria'; import { Button } from 'react-aria-components'; import classNames from 'classnames'; import type { SafeOmit } from '@shoptet/utils'; import { forwardRef } from '@shoptet/utils'; import type { SafeExtract, Size } from '../../../types'; import { Text } from '../../Typography/Text/Text'; /** @inheritdoc */ export interface SingleSelectTriggerProps extends SafeOmit { /** * Sets the accessibility label for the trigger button. */ label: string; /** * Placeholder text displayed when no option is selected. */ placeholder?: string; /** * The width of the trigger button. * @default 'md' */ width?: SafeExtract; /** * Display error state. */ error?: boolean; /** * Display warning state. */ warning?: boolean; /** * Icon type for the trigger. */ icon?: false | 'search' | 'picker'; /** * Currently selected value. */ value?: T | null; /** * Function to get the label for a given option. */ getOptionLabel(option: T): string; /** * Current search query (for filtered selects). */ searchQuery?: string | null; /** * Custom render function for the selected value. */ renderValue?(value: T | null, labelId: string): React.ReactNode; } export const SingleSelectTrigger = forwardRef(function SingleSelectTrigger( { icon, value: valueProp, searchQuery, renderValue, getOptionLabel, placeholder, width = 'md', error, warning, label, isDisabled, ...props }: SingleSelectTriggerProps, forwardedRef: ForwardedRef ) { const optionLabel = valueProp && getOptionLabel(valueProp); const triggerClassName = classNames('singleSelectField__inputTrigger', 'searchField', width, { 'singleSelectField__inputTrigger--picker': icon === 'picker', 'searchField--icon': icon === 'search', 'error-field': error, 'warning-field': warning, }); const generatedId = useId(); const labelledById = `SingleSelectTrigger${generatedId}`; const buttonId = props.id ?? `SingleSelectTriggerButton${generatedId}`; // A single composed aria-label (",