import React, { forwardRef } from 'react'; import styled from 'styled-components'; import cuid from 'cuid'; import isChromatic from 'chromatic/isChromatic'; import KeyboardArrowDown from '../../assets/icons/KeyboardArrowDown'; import { Spacer } from '../../foundations/Layout'; import { filterGlobalProps } from '@lendi-ui/commons/utils'; import { InputBaseComponent, ErrorText, HelpText, FieldLabel } from '../TextField'; import type { InputFieldBaseProps, InputProps } from '../TextField'; import { useTheme } from '../../foundations/Theme'; export interface Option { label: string; value: string; } export interface OptGroup { header: string; options: Option[]; } type Options = Array; interface SelectFieldProps extends InputFieldBaseProps { /** * If the form field is asking for information that fits one of the options in the spec, use pass it here. This is _required when applicable_ for accessibility purposes. https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field */ autoComplete?: 'honorific-prefix'; /** * The name of the select element, used when submitting an HTML form. */ name?: string; inlineAction?: never; /** * Options array. An option value cannot be an empty string, as that is reserved for the placeholder. */ options: Options; maxCharCount?: never; minCharCount?: never; } export type SelectFieldComponentProps = InputProps; // TODO: if placeholder is active, color should be 600 // prettier-ignore const Select = styled(InputBaseComponent as any).attrs({ as: 'select' })` appearance: none; display: flex; align-items: center; padding-top: 0; padding-bottom: 0; padding-right: 40px; color: ${({ theme }) => theme.color.text.main}; &:disabled { color: ${({ theme }) => theme.color.text.subtle}; } `; const Arrow = styled(KeyboardArrowDown)` position: absolute; right: 0.75em; top: 50%; margin-top: calc(-0.75em + 1px); /* Using em because without this styling it was defaulting to 1em, so just keeping consistent with that behaviour */ width: 1.5em; height: 1.5em; pointer-events: none; `; const Wrapper = styled.div` position: relative; width: 100%; `; function SelectFieldComponent( { name, inputId, validationState, helpText, errorText, placeholder, label, ariaLabel, ariaLabelledBy, labelSuffix, isRequired, isDisabled, width = '100%', minWidth, maxWidth, options, onChange, defaultValue, value, ...props }: SelectFieldComponentProps, ref: React.Ref ) { const globalProps = filterGlobalProps(props); const selectElId = isChromatic() ? '1' : inputId ?? cuid(); const helpTextId = isChromatic() ? '2' : cuid(); const errorTextId = isChromatic() ? '3' : cuid(); const hasError = errorText && validationState === 'invalid'; const hasNoValue = defaultValue === undefined && value === undefined; const theme = useTheme(); const ariaDescribedBy = []; if (helpText) { ariaDescribedBy.push(helpTextId); } if (hasError) { ariaDescribedBy.push(errorTextId); } return ( {label && } {helpText && } {hasError && errorText && } ); } export const SelectField = forwardRef(SelectFieldComponent);