feat: enhance form components with additional props for validation and tooltips; add OptionsField component

pull/21398/head
twwu 1 year ago
parent 0345eb4659
commit 6eef5990c9

@ -2,18 +2,26 @@ import React from 'react'
import { useFieldContext } from '../..' import { useFieldContext } from '../..'
import Label from '../label' import Label from '../label'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import type { InputNumberProps } from '../../../input-number'
import { InputNumber } from '../../../input-number' import { InputNumber } from '../../../input-number'
type TextFieldProps = { type TextFieldProps = {
label: string label: string
isRequired?: boolean
showOptional?: boolean
tooltip?: string
className?: string className?: string
labelClassName?: string labelClassName?: string
} } & Omit<InputNumberProps, 'id' | 'value' | 'onChange' | 'onBlur'>
const NumberInputField = ({ const NumberInputField = ({
label, label,
isRequired,
showOptional,
tooltip,
className, className,
labelClassName, labelClassName,
...inputProps
}: TextFieldProps) => { }: TextFieldProps) => {
const field = useFieldContext<number | undefined>() const field = useFieldContext<number | undefined>()
@ -22,13 +30,17 @@ const NumberInputField = ({
<Label <Label
htmlFor={field.name} htmlFor={field.name}
label={label} label={label}
labelClassName={labelClassName} isRequired={isRequired}
showOptional={showOptional}
tooltip={tooltip}
className={labelClassName}
/> />
<InputNumber <InputNumber
id={field.name} id={field.name}
value={field.state.value} value={field.state.value}
onChange={value => field.handleChange(value)} onChange={value => field.handleChange(value)}
onBlur={field.handleBlur} onBlur={field.handleBlur}
{...inputProps}
/> />
</div> </div>
) )

@ -0,0 +1,34 @@
import cn from '@/utils/classnames'
import { useFieldContext } from '../..'
import Label from '../label'
import ConfigSelect from '@/app/components/app/configuration/config-var/config-select'
type OptionsFieldProps = {
label: string;
className?: string;
labelClassName?: string;
}
const OptionsField = ({
label,
className,
labelClassName,
}: OptionsFieldProps) => {
const field = useFieldContext<string[]>()
return (
<div className={cn('flex flex-col gap-y-0.5', className)}>
<Label
htmlFor={field.name}
label={label}
className={labelClassName}
/>
<ConfigSelect
options={field.state.value}
onChange={value => field.handleChange(value)}
/>
</div>
)
}
export default OptionsField

@ -11,6 +11,9 @@ type SelectOption = {
type SelectFieldProps = { type SelectFieldProps = {
label: string label: string
options: SelectOption[] options: SelectOption[]
isRequired?: boolean
showOptional?: boolean
tooltip?: string
className?: string className?: string
labelClassName?: string labelClassName?: string
} }
@ -18,6 +21,9 @@ type SelectFieldProps = {
const SelectField = ({ const SelectField = ({
label, label,
options, options,
isRequired,
showOptional,
tooltip,
className, className,
labelClassName, labelClassName,
}: SelectFieldProps) => { }: SelectFieldProps) => {
@ -27,8 +33,11 @@ const SelectField = ({
<div className={cn('flex flex-col gap-y-0.5', className)}> <div className={cn('flex flex-col gap-y-0.5', className)}>
<Label <Label
htmlFor={field.name} htmlFor={field.name}
className={labelClassName}
label={label} label={label}
isRequired={isRequired}
showOptional={showOptional}
tooltip={tooltip}
className={labelClassName}
/> />
<PureSelect <PureSelect
value={field.state.value} value={field.state.value}

@ -1,19 +1,26 @@
import React from 'react' import React from 'react'
import { useFieldContext } from '../..' import { useFieldContext } from '../..'
import Input from '../../../input' import Input, { type InputProps } from '../../../input'
import Label from '../label' import Label from '../label'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
type TextFieldProps = { type TextFieldProps = {
label: string label: string
isRequired?: boolean
showOptional?: boolean
tooltip?: string
className?: string className?: string
labelClassName?: string labelClassName?: string
} } & Omit<InputProps, 'className' | 'onChange' | 'onBlur' | 'value' | 'id'>
const TextField = ({ const TextField = ({
label, label,
isRequired,
showOptional,
tooltip,
className, className,
labelClassName, labelClassName,
...inputProps
}: TextFieldProps) => { }: TextFieldProps) => {
const field = useFieldContext<string>() const field = useFieldContext<string>()
@ -22,13 +29,17 @@ const TextField = ({
<Label <Label
htmlFor={field.name} htmlFor={field.name}
label={label} label={label}
labelClassName={labelClassName} isRequired={isRequired}
showOptional={showOptional}
tooltip={tooltip}
className={labelClassName}
/> />
<Input <Input
id={field.name} id={field.name}
value={field.state.value} value={field.state.value}
onChange={e => field.handleChange(e.target.value)} onChange={e => field.handleChange(e.target.value)}
onBlur={field.handleBlur} onBlur={field.handleBlur}
{...inputProps}
/> />
</div> </div>
) )

@ -1,14 +1,14 @@
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import Tooltip from '../../tooltip' import Tooltip from '../../tooltip'
import { useTranslation } from 'react-i18next'
type LabelProps = { export type LabelProps = {
htmlFor: string htmlFor: string
label: string label: string
isRequired?: boolean isRequired?: boolean
showOptional?: boolean showOptional?: boolean
tooltip?: string tooltip?: string
className?: string className?: string
labelClassName?: string
} }
const Label = ({ const Label = ({
@ -17,17 +17,19 @@ const Label = ({
isRequired, isRequired,
showOptional, showOptional,
tooltip, tooltip,
labelClassName, className,
}: LabelProps) => { }: LabelProps) => {
const { t } = useTranslation()
return ( return (
<div className='flex h-6 items-center'> <div className='flex h-6 items-center'>
<label <label
htmlFor={htmlFor} htmlFor={htmlFor}
className={cn('system-sm-medium text-text-secondary', labelClassName)} className={cn('system-sm-medium text-text-secondary', className)}
> >
{label} {label}
</label> </label>
{showOptional && <div className='system-xs-regular ml-1 text-text-tertiary'>(Optional)</div>} {showOptional && <div className='system-xs-regular ml-1 text-text-tertiary'>{t('common.label.optional')}</div>}
{isRequired && <div className='system-xs-regular ml-1 text-text-destructive-secondary'>*</div>} {isRequired && <div className='system-xs-regular ml-1 text-text-destructive-secondary'>*</div>}
{tooltip && ( {tooltip && (
<Tooltip <Tooltip

@ -3,6 +3,7 @@ import TextField from './components/field/text'
import NumberInputField from './components/field/number-input' import NumberInputField from './components/field/number-input'
import CheckboxField from './components/field/checkbox' import CheckboxField from './components/field/checkbox'
import SelectField from './components/field/select' import SelectField from './components/field/select'
import OptionsField from './components/field/options'
import SubmitButton from './components/form/submit-button' import SubmitButton from './components/form/submit-button'
export const { fieldContext, useFieldContext, formContext, useFormContext } export const { fieldContext, useFieldContext, formContext, useFormContext }
@ -14,6 +15,7 @@ export const { useAppForm, withForm } = createFormHook({
NumberInputField, NumberInputField,
CheckboxField, CheckboxField,
SelectField, SelectField,
OptionsField,
}, },
formComponents: { formComponents: {
SubmitButton, SubmitButton,

Loading…
Cancel
Save