import * as React from 'react'; import QuestionCircleOutlined from '@ant-design/icons/QuestionCircleOutlined'; import classNames from 'classnames'; import type { ColProps } from '../grid/col'; import Col from '../grid/col'; import { useLocale } from '../locale'; import defaultLocale from '../locale/en_US'; import type { TooltipProps } from '../tooltip'; import Tooltip from '../tooltip'; import type { FormContextProps } from './context'; import { FormContext } from './context'; import type { RequiredMark } from './Form'; import type { FormLabelAlign } from './interface'; export type WrapperTooltipProps = TooltipProps & { icon?: React.ReactElement; }; export type LabelTooltipType = WrapperTooltipProps | React.ReactNode; function toTooltipProps(tooltip: LabelTooltipType): WrapperTooltipProps | null { if (!tooltip) { return null; } if (typeof tooltip === 'object' && !React.isValidElement(tooltip)) { return tooltip as WrapperTooltipProps; } return { title: tooltip, }; } export interface FormItemLabelProps { colon?: boolean; htmlFor?: string; label?: React.ReactNode; labelAlign?: FormLabelAlign; labelCol?: ColProps; /** * @internal Used for pass `requiredMark` from `
` */ requiredMark?: RequiredMark; tooltip?: LabelTooltipType; } const FormItemLabel: React.FC = ({ prefixCls, label, htmlFor, labelCol, labelAlign, colon, required, requiredMark, tooltip, }) => { const [formLocale] = useLocale('Form'); const { vertical, labelAlign: contextLabelAlign, labelCol: contextLabelCol, labelWrap, colon: contextColon, } = React.useContext(FormContext); if (!label) { return null; } const mergedLabelCol: ColProps = labelCol || contextLabelCol || {}; const mergedLabelAlign: FormLabelAlign | undefined = labelAlign || contextLabelAlign; const labelClsBasic = `${prefixCls}-item-label`; const labelColClassName = classNames( labelClsBasic, mergedLabelAlign === 'left' && `${labelClsBasic}-left`, mergedLabelCol.className, { [`${labelClsBasic}-wrap`]: !!labelWrap, }, ); let labelChildren: React.ReactNode = label; // Keep label is original where there should have no colon const computedColon = colon === true || (contextColon !== false && colon !== false); const haveColon = computedColon && !vertical; // Remove duplicated user input colon if (haveColon && typeof label === 'string' && (label as string).trim() !== '') { labelChildren = (label as string).replace(/[:|:]\s*$/, ''); } // Tooltip const tooltipProps = toTooltipProps(tooltip); if (tooltipProps) { const { icon = , ...restTooltipProps } = tooltipProps; const tooltipNode: React.ReactNode = ( {React.cloneElement(icon, { className: `${prefixCls}-item-tooltip`, title: '', onClick: (e: React.MouseEvent) => { // Prevent label behavior in tooltip icon // https://github.com/ant-design/ant-design/issues/46154 e.preventDefault(); }, tabIndex: null, })} ); labelChildren = ( <> {labelChildren} {tooltipNode} ); } // Required Mark const isOptionalMark = requiredMark === 'optional'; const isRenderMark = typeof requiredMark === 'function'; if (isRenderMark) { labelChildren = requiredMark(labelChildren, { required: !!required }); } else if (isOptionalMark && !required) { labelChildren = ( <> {labelChildren} {formLocale?.optional || defaultLocale.Form?.optional} ); } const labelClassName = classNames({ [`${prefixCls}-item-required`]: required, [`${prefixCls}-item-required-mark-optional`]: isOptionalMark || isRenderMark, [`${prefixCls}-item-no-colon`]: !computedColon, }); return ( ); }; export default FormItemLabel;