import cns from 'classnames'
import React, { CSSProperties, ReactNode } from 'react'
import { ComponentSize, usePrefix } from '../ConfigProvider'
import { concat } from '../utils'
import {
ValidateMessage, validateResultCtx, ValidateStatus, ValidateResult, defaultValidateStatus,
Layout, LayoutType, defaultLabelAlign, useFormSize, useFormLayout, sizeCtx, layoutCtx,
useLabelColorMap, defaultLabelColor, LabelOptions, useFormLabelOptions, defaultLabelVerticalAlign,
defaultLabelWidth, defaultLabelGapForHorizontal, defaultLabelGapForInline, useFormVerticalGap
} from './defs'
export interface Props extends LabelOptions {
/** 内容尺寸 */
size?: ComponentSize
/** 内容布局 */
layout?: LayoutType | Layout
/** 表单项名称 */
label?: ReactNode
/** 输入提示信息 */
tip?: ReactNode
/** 校验状态 */
validateStatus?: ValidateStatus
/** 校验结果信息 */
validateMessage?: ValidateMessage
/** 是否必填(会在 label 处展示对应的标识) */
required?: boolean
/** 自定义样式名 */
className?: string
/** 自定义样式 */
style?: CSSProperties
/** 表单项内容 */
children?: ReactNode
}
export default function FormItem(props: Props) {
const prefix = usePrefix('form-item')
const size = useFormSize(props.size)
const layout = useFormLayout(props.layout)
const labelOptions = useFormLabelOptions({
labelWidth: props.labelWidth,
labelGap: props.labelGap,
labelAlign: props.labelAlign,
labelColor: props.labelColor,
labelVerticalAlign: props.labelVerticalAlign
})
const verticalGap = useFormVerticalGap(undefined)
const labelColorMap = useLabelColorMap()
const validateStatus = props.validateStatus ?? defaultValidateStatus
const className = cns(
prefix,
props.className,
concat(prefix, 'size', size),
concat(prefix, 'layout', layout.type),
concat(prefix, 'validate-status', validateStatus)
)
const style: CSSProperties = {
marginBottom: verticalGap,
...props.style
}
const labelClassName = cns(
concat(prefix, 'label'),
props.required && concat(prefix, 'label', 'required'),
layout.type === 'horizontal' && concat(prefix, 'label', 'align', labelOptions.labelAlign ?? defaultLabelAlign),
layout.type === 'horizontal' && concat(prefix, 'label', 'vertical-align', labelOptions.labelVerticalAlign ?? defaultLabelVerticalAlign)
)
const labelMarginRight = (() => {
if (layout.type === 'horizontal') return labelOptions.labelGap ?? defaultLabelGapForHorizontal
if (layout.type === 'inline') return labelOptions.labelGap ?? defaultLabelGapForInline
})()
const labelStyle: CSSProperties = {
flexBasis: layout.type === 'horizontal' ? (labelOptions.labelWidth ?? defaultLabelWidth) : undefined,
color: labelColorMap[labelOptions.labelColor ?? defaultLabelColor],
marginRight: labelMarginRight
}
const validateResult: ValidateResult = {
status: validateStatus,
message: props.validateMessage
}
const tipView = props.tip != null &&