import React, { useState } from 'react'; import { Form, Popover, Progress, Space } from 'antd'; import type { FormItemProps, PopoverProps, ProgressProps, FormInstance } from 'antd'; import { CheckCircleFilled, CloseCircleFilled, LoadingOutlined } from '@ant-design/icons'; import type { Rule, NamePath, RuleObject } from 'rc-field-form/lib/interface'; const RED = '#ff4d4f'; const YELLOW = '#faad14'; const GREEN = '#52c41a'; const PRIMARY = '#1890ff'; const COLORS = { RED, YELLOW, GREEN, PRIMARY }; const getStrokeColor = (percent: number) => { if (percent < 50) { return COLORS.RED; } if (percent < 100) { return COLORS.YELLOW; } return COLORS.GREEN; }; const CircleRender = () => { return (
); }; const getIcon = ( fieldError: string[], rule: Rule, isTouched: boolean, requiredChecked: boolean, ) => { if (!isTouched) { return ; } if (!requiredChecked) { return ; } if (fieldError.includes((rule as any).message)) { return ; } return ; }; const Content: React.FC<{ fieldError: string[]; value: any; isValidating: boolean; isTouched: boolean; rules: Rule[]; progressProps?: ProgressProps | false; }> = ({ rules, isTouched, isValidating, value, fieldError, progressProps }) => { const percent = Math.max( 0, Math.min(100, ((rules.length - fieldError.length) / rules.length) * 100), ); const isSingleRule = rules.length === 1; const requiredRule = rules.filter((_) => (_ as RuleObject).required)[0] as RuleObject; const hasRequired = !!requiredRule; const requiredChecked = hasRequired && !fieldError.includes(requiredRule?.message as string); return (
{(progressProps === undefined || progressProps) && ( )}
    {rules?.map((rule, idx) => (
  • {isValidating ? ( ) : ( getIcon(fieldError, rule, isTouched, hasRequired ? requiredChecked : true) )} {(rule as any).message}
  • ))}
); }; interface InlineErrorFormItemProps extends FormItemProps { errorType?: 'popover' | 'default'; popoverProps?: PopoverProps; progressProps?: ProgressProps | false; } interface InternalProps extends InlineErrorFormItemProps { name: NamePath; rules: Rule[]; } const FIX_INLINE_STYLE = { marginTop: -5, marginBottom: -5, marginLeft: 0, marginRight: 0, }; const InternalFormItem: React.FC< InternalProps & { form: Omit; } > = ({ label, rules, name, children, popoverProps, progressProps, form, ...rest }) => { const fieldError = form.getFieldError(name); const value = form.getFieldValue(name); const isValidating = form.isFieldValidating(name); const isTouched = form.isFieldTouched(name); const [visible, setVisible] = useState(undefined); return ( { return ( } >
{input} {extra}
); }, }} {...rest} > {children}
); }; const InlineErrorFormItem: React.FC = (props) => { return ( {(form) => { return ; }} ); }; export default (props: InlineErrorFormItemProps) => { const { errorType, rules, name, popoverProps, children, progressProps, ...rest } = props; if (name && rules?.length && errorType === 'popover') { return ( 1 ? progressProps : false} {...rest} > {children} ); } return ( {children} ); };