import * as React from 'react' ; import { space } from '@workday/canvas-kit-react/tokens' ; import { GrowthBehavior , ErrorType , styled , Themeable , generateUniqueId , } from '@workday/canvas-kit-react/common' ; import Hint from './Hint' ; import Label from './Label' ; import { FormFieldLabelPosition , FormFieldLabelPositionBehavior } from './types' ; export interface FormFieldProps extends Themeable , React . HTMLAttributes < HTMLDivElement > , GrowthBehavior { default labelPosition ? : FormFieldLabelPosition ; /**
     * The text of the FormField label.
     */ label ? : React . ReactNode ; /**
     * The text of the message displayed below the input component. This is required if `error` is defined.
     */ hintText ? : React . ReactNode ; /**
     * The HTML `id` of the message displayed below the input component. This is required for the `aria-describedby` accessibility attribute if `error` and `hintText` are defined.
     */ hintId ? : string ; /**
     * The HTML `id` of the input component. If an `id` is not specified for the input, this will be used as it's `id`. This is referenced by the label's `htmlFor` attribute. This is required for accessiblity if `label` is defined.
     */ inputId ? : string ; /**
     * The type of error associated with the FormField (if applicable). This is passed to the input component.
     */ error ? : ErrorType ; default required ? : boolean ; default useFieldset ? : boolean ; /**
     * The input component wrapped by the FormField.
     */ children : React . ReactNode ; default errorLabel ? : string ; default alertLabel ? : string ; } export interface FormFieldErrorBehavior { error ? : ErrorType ; } const FormFieldFieldsetContainer = styled ( 'fieldset' ) < GrowthBehavior & FormFieldLabelPositionBehavior > ( ( { grow , labelPosition } ) => ( { display : labelPosition === FormFieldLabelPosition . Top ? 'inline-block' : 'flex' , flexGrow : grow ? 1 : undefined , padding : 0 , border : 0 , margin : 0 , marginBottom : space . m , } ) ) ; const FormFieldContainer = styled ( 'div' ) < FormFieldLabelPositionBehavior & FormFieldProps > ( ( { labelPosition , useFieldset } ) => { if ( useFieldset ) { return { display : 'flex' , } ; } if ( labelPosition === FormFieldLabelPosition . Left ) { return { display : 'flex' , marginBottom : space . m , } ; } return { display : 'block' , marginBottom : space . m , } ; } ) ; const FormFieldInputContainer = styled ( 'div' ) < GrowthBehavior & FormFieldLabelPositionBehavior > ( ( { grow , labelPosition } ) => { if ( grow ) { if ( labelPosition === FormFieldLabelPosition . Left || labelPosition === FormFieldLabelPosition . Hidden ) { return { flexGrow : 1 , } ; } return { width : '100%' , display : 'block' , } ; } if ( labelPosition === FormFieldLabelPosition . Left ) { return { display : 'inline-flex' , alignItems : 'center' , flexWrap : 'wrap' , } ; } return { display : 'inline-block' , } ; } ) ; class FormField extends React . Component < FormFieldProps > { static LabelPosition = FormFieldLabelPosition ; static ErrorType = ErrorType ; private inputId : string = this . props . inputId || generateUniqueId ( ) ; private renderChildren = ( child ) : React . ReactNode => { if ( React . isValidElement ( child ) ) { const props = { ... child . props , } ; if ( this . props . grow ) { props . grow = this . props . grow ; } if ( typeof this . props . error !== 'undefined' ) { props . error = this . props . error ; if ( this . props . hintId ) { props [ 'aria-describedby' ] = this . props . hintId ; } if ( this . props . error === ErrorType . Error ) { props [ 'aria-invalid' ] = true ; } } props . id = this . inputId ; return React . cloneElement ( child , props ) ; } return child ; } ; render ( ) { const { errorLabel = 'Error' , alertLabel = 'Alert' , useFieldset = false , labelPosition = FormField . LabelPosition . Top , label , hintText , hintId , inputId , grow , children , error , required , ... elemProps } = this . props ; const field = ( < > { typeof label === 'string' ? ( < Label labelPosition = { labelPosition } htmlFor = { this . inputId } isLegend = { useFieldset } required = { required } accessibleHide = { labelPosition === FormFieldLabelPosition . Hidden } > { label } < /Label>) : (label)} < FormFieldInputContainer grow = { grow } labelPosition = { labelPosition } > { React . Children . map ( children , this . renderChildren ) } { hintText && ( < Hint errorLabel = { errorLabel } alertLabel = { alertLabel } error = { error } id = { hintId } > { hintText } < /Hint>)} < /FormFieldInputContainer> < />); if ( useFieldset ) { return ( < FormFieldContainer useFieldset = { useFieldset } labelPosition = { labelPosition } { ... elemProps } > < FormFieldFieldsetContainer grow = { grow } labelPosition = { labelPosition } > { field } < /FormFieldFieldsetContainer> < /FormFieldContainer>); } else { return ( < FormFieldContainer useFieldset = { useFieldset } labelPosition = { labelPosition } { ... elemProps } > { field } < /FormFieldContainer>); } } } FormField . LabelPosition = FormFieldLabelPosition ; FormField . ErrorType = ErrorType ; export default FormField ;