import { Component, createRef } from 'react'; import classNames from 'classnames'; import { IInputProps, IInputCoreProps, IInputClearEvent } from './types'; import { InputCore } from './InputCore'; import { TextArea } from './TextArea'; import { InputContext, IInputContext } from './context'; import { IDisabledContext, DisabledContext } from '../disabled'; import omit from '../utils/omit'; export interface IInputState { hasFocus: boolean; } const BLOCKED_CHILD_PROPS = [ 'className', 'width', 'style', 'size', 'disabled', 'widthSize', ] as const; export class Input extends Component { static contextType = InputContext; static displayName = 'ZentInput'; static defaultProps = { type: 'text', size: 'normal', }; context!: IInputContext; elementRef = createRef(); /** * backward compatibility */ get input() { return this.elementRef.current; } state = { hasFocus: false, }; focus() { const el = this.elementRef.current; el && el.focus(); } select(selectionStart?: number, selectionEnd?: number) { const el = this.elementRef.current; if (!el) { return; } if ( typeof selectionStart === 'number' && typeof selectionEnd === 'number' ) { el.setSelectionRange(selectionStart, selectionEnd); } else { el.select(); } } onKeyDown = ( e: | React.KeyboardEvent | React.KeyboardEvent ) => { const { onKeyDown, onPressEnter } = this.props; if (onPressEnter && e.key === 'Enter') { onPressEnter(e as any); } onKeyDown && onKeyDown(e as any); }; onFocus: React.FocusEventHandler = evt => { this.setState({ hasFocus: true, }); const { onFocus } = this.props; onFocus && onFocus(evt as any); }; onBlur: React.FocusEventHandler = evt => { this.setState({ hasFocus: false, }); const { onBlur } = this.props; onBlur && onBlur(evt as any); }; clearInput: React.MouseEventHandler = evt => { const { onChange } = this.props; const e: IInputClearEvent = Object.create(evt); e.target = { ...(this.props as IInputCoreProps), value: '', }; e.fromClearButton = true; onChange && onChange(e as any); }; componentDidMount() { const { autoFocus, autoSelect, initSelectionStart, initSelectionEnd } = this.props; const el = this.elementRef.current; if (autoFocus) { el && el.focus(); } if (autoSelect) { this.select(initSelectionStart, initSelectionEnd); } } renderImpl(disableCtx: IDisabledContext) { const props = this.props; const { type, className, width, style, size, disabled = disableCtx.value, readOnly, widthSize, } = props; const { hasFocus } = this.state; const isTextarea = type.toLowerCase() === 'textarea'; const editable = !(disabled || readOnly); const { renderInner } = this.context; const wrapperStyle: React.CSSProperties = { ...style, width, }; let isOutOfRange = false; let children: React.ReactNode; if (props.type === 'textarea') { const textValue = this.elementRef.current?.value; isOutOfRange = !!props.maxCharacterCount && !!textValue ? textValue.length > props.maxCharacterCount : false; children = (