import React from 'react' import Button from '../Button/Button' import { hasValue } from '../../services/HelperServiceTyped' import Tooltip from '../Tooltip/Tooltip' import { type TooltipProps } from '../Tooltip/Tooltip' import FormLabel from '../FormLabel/FormLabel' import styles from './_picker.module.scss' import { type ButtonProps } from '../Button/Button.models' export default function Picker< OptionGeneric extends RequiredOptionKeys, StateGeneric, >({ options, state, callout, stateName, customClass, valuesAreBooleans, disabled, exposedFilterVariant, }: StateAndStateNameProps): React.JSX.Element export default function Picker< OptionGeneric extends RequiredOptionKeys, StateGeneric, >({ options, selected, callout, customClass, valuesAreBooleans, disabled, exposedFilterVariant, }: SelectedProps): React.JSX.Element export default function Picker< OptionGeneric extends RequiredOptionKeys, StateGeneric, >({ options, selected, state, callout, stateName, customClass, valuesAreBooleans = false, disabled = false, error = false, required, labelText, rightLabel, labelTooltip, tooltip, qaTestId = 'picker', exposedFilterVariant = false, }: PickerProps): React.JSX.Element { const inlineStyles = { '--options-length': options.length, } as React.CSSProperties const renderPicker = () => { const isActive = (optionValue: OptionGeneric['value']) => { if (valuesAreBooleans) { return optionValue === selected } return ( optionValue === (selected || (state as Record)?.[stateName ?? '']) ) } return (
{options.map((e, i) => { const active = isActive(e.value) const buttonElement = ( ) // For exposedFilterVariant, wrap individual buttons with tooltips if provided if ( exposedFilterVariant && 'tooltip' in e && e.tooltip && e.tooltip.tooltipContent ) { return ( {buttonElement} ) } return ( {buttonElement} ) })}
) } return (
{labelText && ( )} {/* Note: When exposedFilterVariant is true and individual option tooltips are provided, the picker-level tooltip prop should not be used to avoid nested/conflicting tooltips. Individual option tooltips take precedence in this case. */} {tooltip && !( exposedFilterVariant && options.some((opt) => 'tooltip' in opt && opt.tooltip?.tooltipContent) ) ? ( {renderPicker()} ) : ( renderPicker() )}
) } /** * pass in an array of options to select that will be mapped out and styled for you * - then pass in what value is currently selected in state or pass in a state object * w/ fieldName and the component will show that option as selected - state needs to * be managed outside of this component and in the file you are consuming it in. **/ interface RequiredOptionKeys { id?: number text?: string value: ValueTypeGeneric /** Tooltip to display on hover for each option button (only available when exposedFilterVariant is true) */ tooltip?: Omit } type Selected = string | number | boolean // Helper type to conditionally exclude tooltip when exposedFilterVariant is not true type OptionsWithoutTooltip = T extends { tooltip?: unknown } ? Omit : T type PickerBaseProps< OptionGeneric extends RequiredOptionKeys, > = { customClass?: string valuesAreBooleans?: boolean disabled?: boolean labelText?: string rightLabel?: React.ReactNode labelTooltip?: Omit required?: boolean error?: boolean /** Optional prop to add a test id to the Picker for QA testing */ qaTestId?: string } & ( | { /** Use the exposed filter variant styling - when true, options can include tooltip */ exposedFilterVariant: true options: OptionGeneric[] } | { /** Use the exposed filter variant styling - when false/undefined, options cannot have tooltip */ exposedFilterVariant?: false options: Array> } ) type StateAndStateNameCallout = ( param1: string, param2: Param2Generic, ) => void // if you use state, then it and stateName are both required. type StateAndStateNameProps< OptionGeneric extends RequiredOptionKeys, StateGeneric, > = PickerBaseProps & { state: StateGeneric stateName: string selected?: Selected callout: StateAndStateNameCallout tooltip?: ButtonProps['tooltip'] } type SelectedPropsCallout = (param1: Param1Generic) => void // if you use selected, then it's required... unless there isn't anything selected yet. Then it's optional type SelectedProps< OptionGeneric extends RequiredOptionKeys, StateGeneric, > = PickerBaseProps & { state?: StateGeneric stateName?: string selected?: Selected callout: SelectedPropsCallout tooltip?: ButtonProps['tooltip'] } export type PickerProps< OptionGeneric extends RequiredOptionKeys, StateGeneric, > = | SelectedProps | StateAndStateNameProps // here's an example of passed in options // [ // { id: 0, text: 'SNOWBOARDING', value: 'SNOWBOARDING' }, // { id: 1, text: 'SKIING', value: 'SKIING' }, // ] // selected value could be - 'SNOWBOARDING' // or if state obj and stateName i.e. key value pair - {preferred_method: 'SNOWBOARDING'} and would // statifsy component