import React, { ChangeEvent, FormEvent, KeyboardEvent, ReactElement, ReactNode, useEffect, useState } from 'react' import InputElement from './InputElement' import Label from './Label' import styles from './index.module.css' import { ErrorMessage, FieldInputProps, useField } from 'formik' import classNames from 'classnames/bind' import Disclaimer from './Disclaimer' import Tooltip from '@shared/atoms/Tooltip' import Markdown from '@shared/Markdown' import FormHelp from './Help' import { AssetSelectionAsset } from '@shared/FormInput/InputElement/AssetSelection' import { BoxSelectionOption } from '@shared/FormInput/InputElement/BoxSelection' import { getObjectPropertyByPath } from '@utils/index' const cx = classNames.bind(styles) export interface InputProps { name: string label?: string | ReactNode placeholder?: string required?: boolean help?: string prominentHelp?: boolean tag?: string type?: string options?: string[] | AssetSelectionAsset[] | BoxSelectionOption[] sortOptions?: boolean fields?: FieldInputProps[] methods?: boolean innerFields?: any additionalComponent?: ReactElement value?: string | number onChange?( e: | FormEvent | ChangeEvent | ChangeEvent | ChangeEvent ): void onKeyPress?( e: | KeyboardEvent | KeyboardEvent | KeyboardEvent | KeyboardEvent ): void rows?: number multiple?: boolean pattern?: string min?: string max?: string disabled?: boolean readOnly?: boolean field?: FieldInputProps form?: any prefix?: string | ReactElement postfix?: string | ReactElement step?: string defaultChecked?: boolean size?: 'mini' | 'small' | 'large' | 'default' className?: string checked?: boolean disclaimer?: string disclaimerValues?: string[] } function checkError(form: any, field: FieldInputProps) { const touched = getObjectPropertyByPath(form?.touched, field?.name) const errors = getObjectPropertyByPath(form?.errors, field?.name) return ( touched && errors && !field.name.endsWith('.files') && !field.name.endsWith('.links') && !field.name.endsWith('consumerParameters') ) } export default function Input(props: Partial): ReactElement { const { label, help, prominentHelp, additionalComponent, size, form, field, disclaimer, disclaimerValues } = props const isFormikField = typeof field !== 'undefined' // TODO: this feels hacky as it assumes nested `values` store. But we can't use the // `useField()` hook in here to get `meta.error` so we have to match against form?.errors? // handling flat and nested data at same time. const hasFormikError = checkError(form, field) const styleClasses = cx({ field: true, hasError: hasFormikError }) const [disclaimerVisible, setDisclaimerVisible] = useState(true) useEffect(() => { if (!isFormikField) return if (disclaimer && disclaimerValues) { setDisclaimerVisible( disclaimerValues.includes( getObjectPropertyByPath(props.form?.values, field?.name) ) ) } }, [isFormikField, props.form?.values]) return (
{help && prominentHelp && {help}} {field?.name !== 'files' && isFormikField && hasFormikError && (
)} {disclaimer && ( {disclaimer} )} {additionalComponent && additionalComponent}
) }