/* eslint-disable dot-notation */ import React, { useRef, useState } from "react"; import classNames from "classnames"; import { StyledProps, Omit } from "../_type"; import { ControlledProps, useDefaultValue } from "../form/controlled"; import { forwardRefWithStatics } from "../_util/forward-ref-with-statics"; import { useConfig } from "../_util/config-context"; import { SizeType } from "../_type/Size"; import { noop } from "../_util/noop"; import { KeyMap } from "../_util/key-map"; import { TextArea } from "./TextArea"; import { InputPassword } from "./InputPassword"; /** * Input 组件支持的属性。 * * 除表格中列出的属性外,支持透传原生 `` 标签支持的属性。 */ export interface InputProps extends ControlledProps, StyledProps, Omit< React.InputHTMLAttributes, "onChange" | "size" | "value" | "defaultValue" > { /** * 占位符 */ placeholder?: string; /** * 是否禁用 * @default false */ disabled?: boolean; /** * 是否为只读模式 * @default false */ readonly?: boolean; /** * 最大输入长度 */ maxLength?: number; /** * 原生 `` 标签 `type` 属性 */ type?: React.InputHTMLAttributes["type"]; /** * 输入框尺寸,使用 `full` 撑满容器宽度 */ size?: SizeType; /** * 按下回车键的回调 * @since 2.7.0 */ onPressEnter?: (value: string, event: React.KeyboardEvent) => void; /** * 改变 Input 的基本样式类名,不建议使用 */ baseClassName?: string; /** * 是否多行输入 * * **\[Deprecated\]** 请使用 `` 组件 * @deprecated */ multiline?: boolean; /** * 行数 * * **\[Deprecated\]** 请使用 `` 组件 * @deprecated */ rows?: number; /** * 是否展示字数 * * **\[Deprecated\]** 请使用 `` 组件 * @deprecated */ showCount?: boolean; /** * Input 组件不应该传入 children */ children?: never; } export const Input = forwardRefWithStatics( (props: InputProps, ref: React.Ref) => { const { classPrefix } = useConfig(); const { children, // never multiline, placeholder, disabled, readonly, size, type, baseClassName, className, style, value, onChange, showCount, onCompositionStart = noop, onCompositionEnd = noop, onKeyPress = noop, onPressEnter = noop, ...restProps } = useDefaultValue(props, ""); const composingRef = useRef(false); // 记录 `composition` 事件过程中值以实现受控 const [composingRefValue, setComposingValue] = useState(""); const basename = baseClassName || `${classPrefix}-${multiline ? "textarea" : "input"}`; const inputClassName = classNames({ [basename]: true, [className]: className, [`size-${size === "full" ? `${size}-width` : size}`]: size, }); const hasRows = multiline && restProps.rows; const inputProps: React.InputHTMLAttributes = { placeholder, className: inputClassName, readOnly: readonly, disabled, // 受样式限制 rows 属性没有生效 style: hasRows ? { height: "auto", ...(style || {}) } : style, value: composingRef.current ? composingRefValue : value, onChange: (event: React.ChangeEvent) => { if (composingRef.current) { setComposingValue(event.target.value); } else { onChange(event.target.value, { event }); } }, onCompositionStart: (event: React.CompositionEvent) => { composingRef.current = true; onCompositionStart(event); }, onCompositionEnd: (event: React.CompositionEvent) => { if (composingRef.current) { composingRef.current = false; onChange(event.currentTarget.value, { event }); } setComposingValue(""); onCompositionEnd(event); }, onKeyPress: (event: React.KeyboardEvent) => { if (event.key === KeyMap.Enter) { onPressEnter(event.currentTarget.value, event); } onKeyPress(event); }, ...restProps, }; if (multiline) { const component =