1
This commit is contained in:
+8
@@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
import type { BaseInputProps } from './interface';
|
||||
export interface HolderRef {
|
||||
/** Provider holder ref. Will return `null` if not wrap anything */
|
||||
nativeElement: HTMLElement | null;
|
||||
}
|
||||
declare const BaseInput: React.ForwardRefExoticComponent<BaseInputProps & React.RefAttributes<HolderRef>>;
|
||||
export default BaseInput;
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
import { clsx } from 'clsx';
|
||||
import React, { cloneElement, useRef } from 'react';
|
||||
import { hasAddon, hasPrefixSuffix } from "./utils/commonUtils";
|
||||
const BaseInput = /*#__PURE__*/React.forwardRef((props, ref) => {
|
||||
const {
|
||||
inputElement: inputEl,
|
||||
children,
|
||||
prefixCls,
|
||||
prefix,
|
||||
suffix,
|
||||
addonBefore,
|
||||
addonAfter,
|
||||
className,
|
||||
style,
|
||||
disabled,
|
||||
readOnly,
|
||||
focused,
|
||||
triggerFocus,
|
||||
allowClear,
|
||||
value,
|
||||
handleReset,
|
||||
hidden,
|
||||
classes,
|
||||
classNames,
|
||||
dataAttrs,
|
||||
styles,
|
||||
components,
|
||||
onClear
|
||||
} = props;
|
||||
const inputElement = children ?? inputEl;
|
||||
const AffixWrapperComponent = components?.affixWrapper || 'span';
|
||||
const GroupWrapperComponent = components?.groupWrapper || 'span';
|
||||
const WrapperComponent = components?.wrapper || 'span';
|
||||
const GroupAddonComponent = components?.groupAddon || 'span';
|
||||
const containerRef = useRef(null);
|
||||
const onInputClick = e => {
|
||||
if (containerRef.current?.contains(e.target)) {
|
||||
triggerFocus?.();
|
||||
}
|
||||
};
|
||||
const hasAffix = hasPrefixSuffix(props);
|
||||
let element = /*#__PURE__*/cloneElement(inputElement, {
|
||||
value,
|
||||
className: clsx(inputElement.props?.className, !hasAffix && classNames?.variant) || null
|
||||
});
|
||||
|
||||
// ======================== Ref ======================== //
|
||||
const groupRef = useRef(null);
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
nativeElement: groupRef.current || containerRef.current
|
||||
}));
|
||||
|
||||
// ================== Prefix & Suffix ================== //
|
||||
if (hasAffix) {
|
||||
// ================== Clear Icon ================== //
|
||||
let clearIcon = null;
|
||||
if (allowClear) {
|
||||
const needClear = !disabled && !readOnly && value;
|
||||
const clearIconCls = `${prefixCls}-clear-icon`;
|
||||
const iconNode = typeof allowClear === 'object' && allowClear?.clearIcon ? allowClear.clearIcon : '✖';
|
||||
clearIcon = /*#__PURE__*/React.createElement("button", {
|
||||
type: "button",
|
||||
tabIndex: -1,
|
||||
onClick: event => {
|
||||
handleReset?.(event);
|
||||
onClear?.();
|
||||
}
|
||||
// Do not trigger onBlur when clear input
|
||||
// https://github.com/ant-design/ant-design/issues/31200
|
||||
,
|
||||
onMouseDown: e => e.preventDefault(),
|
||||
className: clsx(clearIconCls, {
|
||||
[`${clearIconCls}-hidden`]: !needClear,
|
||||
[`${clearIconCls}-has-suffix`]: !!suffix
|
||||
})
|
||||
}, iconNode);
|
||||
}
|
||||
const affixWrapperPrefixCls = `${prefixCls}-affix-wrapper`;
|
||||
const affixWrapperCls = clsx(affixWrapperPrefixCls, {
|
||||
[`${prefixCls}-disabled`]: disabled,
|
||||
[`${affixWrapperPrefixCls}-disabled`]: disabled,
|
||||
// Not used, but keep it
|
||||
[`${affixWrapperPrefixCls}-focused`]: focused,
|
||||
// Not used, but keep it
|
||||
[`${affixWrapperPrefixCls}-readonly`]: readOnly,
|
||||
[`${affixWrapperPrefixCls}-input-with-clear-btn`]: suffix && allowClear && value
|
||||
}, classes?.affixWrapper, classNames?.affixWrapper, classNames?.variant);
|
||||
const suffixNode = (suffix || allowClear) && /*#__PURE__*/React.createElement("span", {
|
||||
className: clsx(`${prefixCls}-suffix`, classNames?.suffix),
|
||||
style: styles?.suffix
|
||||
}, clearIcon, suffix);
|
||||
element = /*#__PURE__*/React.createElement(AffixWrapperComponent, _extends({
|
||||
className: affixWrapperCls,
|
||||
style: styles?.affixWrapper,
|
||||
onClick: onInputClick
|
||||
}, dataAttrs?.affixWrapper, {
|
||||
ref: containerRef
|
||||
}), prefix && /*#__PURE__*/React.createElement("span", {
|
||||
className: clsx(`${prefixCls}-prefix`, classNames?.prefix),
|
||||
style: styles?.prefix
|
||||
}, prefix), element, suffixNode);
|
||||
}
|
||||
|
||||
// ================== Addon ================== //
|
||||
if (hasAddon(props)) {
|
||||
const wrapperCls = `${prefixCls}-group`;
|
||||
const addonCls = `${wrapperCls}-addon`;
|
||||
const groupWrapperCls = `${wrapperCls}-wrapper`;
|
||||
const mergedWrapperClassName = clsx(`${prefixCls}-wrapper`, wrapperCls, classes?.wrapper, classNames?.wrapper);
|
||||
const mergedGroupClassName = clsx(groupWrapperCls, {
|
||||
[`${groupWrapperCls}-disabled`]: disabled
|
||||
}, classes?.group, classNames?.groupWrapper);
|
||||
|
||||
// Need another wrapper for changing display:table to display:inline-block
|
||||
// and put style prop in wrapper
|
||||
element = /*#__PURE__*/React.createElement(GroupWrapperComponent, {
|
||||
className: mergedGroupClassName,
|
||||
ref: groupRef
|
||||
}, /*#__PURE__*/React.createElement(WrapperComponent, {
|
||||
className: mergedWrapperClassName
|
||||
}, addonBefore && /*#__PURE__*/React.createElement(GroupAddonComponent, {
|
||||
className: addonCls
|
||||
}, addonBefore), element, addonAfter && /*#__PURE__*/React.createElement(GroupAddonComponent, {
|
||||
className: addonCls
|
||||
}, addonAfter)));
|
||||
}
|
||||
|
||||
// `className` and `style` are always on the root element
|
||||
return /*#__PURE__*/React.cloneElement(element, {
|
||||
className: clsx(element.props?.className, className) || null,
|
||||
style: {
|
||||
...element.props?.style,
|
||||
...style
|
||||
},
|
||||
hidden
|
||||
});
|
||||
});
|
||||
export default BaseInput;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import React from 'react';
|
||||
import type { InputProps, InputRef } from './interface';
|
||||
declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<InputRef>>;
|
||||
export default Input;
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
import { clsx } from 'clsx';
|
||||
import useControlledState from "@rc-component/util/es/hooks/useControlledState";
|
||||
import omit from "@rc-component/util/es/omit";
|
||||
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
||||
import BaseInput from "./BaseInput";
|
||||
import useCount from "./hooks/useCount";
|
||||
import { resolveOnChange } from "./utils/commonUtils";
|
||||
import { triggerFocus } from "@rc-component/util/es/Dom/focus";
|
||||
const Input = /*#__PURE__*/forwardRef((props, ref) => {
|
||||
const {
|
||||
autoComplete,
|
||||
onChange,
|
||||
onFocus,
|
||||
onBlur,
|
||||
onPressEnter,
|
||||
onKeyDown,
|
||||
onKeyUp,
|
||||
prefixCls = 'rc-input',
|
||||
disabled,
|
||||
htmlSize,
|
||||
className,
|
||||
maxLength,
|
||||
suffix,
|
||||
showCount,
|
||||
count,
|
||||
type = 'text',
|
||||
classes,
|
||||
classNames,
|
||||
styles,
|
||||
onCompositionStart,
|
||||
onCompositionEnd,
|
||||
...rest
|
||||
} = props;
|
||||
const [focused, setFocused] = useState(false);
|
||||
const compositionRef = useRef(false);
|
||||
const keyLockRef = useRef(false);
|
||||
const inputRef = useRef(null);
|
||||
const holderRef = useRef(null);
|
||||
const focus = option => {
|
||||
if (inputRef.current) {
|
||||
triggerFocus(inputRef.current, option);
|
||||
}
|
||||
};
|
||||
|
||||
// ====================== Value =======================
|
||||
const [value, setValue] = useControlledState(props.defaultValue, props.value);
|
||||
const formatValue = value === undefined || value === null ? '' : String(value);
|
||||
|
||||
// =================== Select Range ===================
|
||||
const [selection, setSelection] = useState(null);
|
||||
|
||||
// ====================== Count =======================
|
||||
const countConfig = useCount(count, showCount);
|
||||
const mergedMax = countConfig.max || maxLength;
|
||||
const valueLength = countConfig.strategy(formatValue);
|
||||
const isOutOfRange = !!mergedMax && valueLength > mergedMax;
|
||||
|
||||
// ======================= Ref ========================
|
||||
useImperativeHandle(ref, () => ({
|
||||
focus,
|
||||
blur: () => {
|
||||
inputRef.current?.blur();
|
||||
},
|
||||
setSelectionRange: (start, end, direction) => {
|
||||
inputRef.current?.setSelectionRange(start, end, direction);
|
||||
},
|
||||
select: () => {
|
||||
inputRef.current?.select();
|
||||
},
|
||||
input: inputRef.current,
|
||||
nativeElement: holderRef.current?.nativeElement || inputRef.current
|
||||
}));
|
||||
useEffect(() => {
|
||||
if (keyLockRef.current) {
|
||||
keyLockRef.current = false;
|
||||
}
|
||||
setFocused(prev => prev && disabled ? false : prev);
|
||||
}, [disabled]);
|
||||
const triggerChange = (e, currentValue, info) => {
|
||||
let cutValue = currentValue;
|
||||
if (!compositionRef.current && countConfig.exceedFormatter && countConfig.max && countConfig.strategy(currentValue) > countConfig.max) {
|
||||
cutValue = countConfig.exceedFormatter(currentValue, {
|
||||
max: countConfig.max
|
||||
});
|
||||
if (currentValue !== cutValue) {
|
||||
setSelection([inputRef.current?.selectionStart || 0, inputRef.current?.selectionEnd || 0]);
|
||||
}
|
||||
} else if (info.source === 'compositionEnd') {
|
||||
// Avoid triggering twice
|
||||
// https://github.com/ant-design/ant-design/issues/46587
|
||||
return;
|
||||
}
|
||||
setValue(cutValue);
|
||||
if (inputRef.current) {
|
||||
resolveOnChange(inputRef.current, e, onChange, cutValue);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (selection) {
|
||||
inputRef.current?.setSelectionRange(...selection);
|
||||
}
|
||||
}, [selection]);
|
||||
const onInternalChange = e => {
|
||||
triggerChange(e, e.target.value, {
|
||||
source: 'change'
|
||||
});
|
||||
};
|
||||
const onInternalCompositionEnd = e => {
|
||||
compositionRef.current = false;
|
||||
triggerChange(e, e.currentTarget.value, {
|
||||
source: 'compositionEnd'
|
||||
});
|
||||
onCompositionEnd?.(e);
|
||||
};
|
||||
const handleKeyDown = e => {
|
||||
if (onPressEnter && e.key === 'Enter' && !keyLockRef.current && !e.nativeEvent.isComposing) {
|
||||
keyLockRef.current = true;
|
||||
onPressEnter(e);
|
||||
}
|
||||
onKeyDown?.(e);
|
||||
};
|
||||
const handleKeyUp = e => {
|
||||
if (e.key === 'Enter') {
|
||||
keyLockRef.current = false;
|
||||
}
|
||||
onKeyUp?.(e);
|
||||
};
|
||||
const handleFocus = e => {
|
||||
setFocused(true);
|
||||
onFocus?.(e);
|
||||
};
|
||||
const handleBlur = e => {
|
||||
if (keyLockRef.current) {
|
||||
keyLockRef.current = false;
|
||||
}
|
||||
setFocused(false);
|
||||
onBlur?.(e);
|
||||
};
|
||||
const handleReset = e => {
|
||||
setValue('');
|
||||
focus();
|
||||
if (inputRef.current) {
|
||||
resolveOnChange(inputRef.current, e, onChange);
|
||||
}
|
||||
};
|
||||
|
||||
// ====================== Input =======================
|
||||
const outOfRangeCls = isOutOfRange && `${prefixCls}-out-of-range`;
|
||||
const getInputElement = () => {
|
||||
// Fix https://fb.me/react-unknown-prop
|
||||
const otherProps = omit(props, ['prefixCls', 'onPressEnter', 'addonBefore', 'addonAfter', 'prefix', 'suffix', 'allowClear',
|
||||
// Input elements must be either controlled or uncontrolled,
|
||||
// specify either the value prop, or the defaultValue prop, but not both.
|
||||
'defaultValue', 'showCount', 'count', 'classes', 'htmlSize', 'styles', 'classNames', 'onClear']);
|
||||
return /*#__PURE__*/React.createElement("input", _extends({
|
||||
autoComplete: autoComplete
|
||||
}, otherProps, {
|
||||
onChange: onInternalChange,
|
||||
onFocus: handleFocus,
|
||||
onBlur: handleBlur,
|
||||
onKeyDown: handleKeyDown,
|
||||
onKeyUp: handleKeyUp,
|
||||
className: clsx(prefixCls, {
|
||||
[`${prefixCls}-disabled`]: disabled
|
||||
}, classNames?.input),
|
||||
style: styles?.input,
|
||||
ref: inputRef,
|
||||
size: htmlSize,
|
||||
type: type,
|
||||
onCompositionStart: e => {
|
||||
compositionRef.current = true;
|
||||
onCompositionStart?.(e);
|
||||
},
|
||||
onCompositionEnd: onInternalCompositionEnd
|
||||
}));
|
||||
};
|
||||
const getSuffix = () => {
|
||||
// Max length value
|
||||
const hasMaxLength = Number(mergedMax) > 0;
|
||||
if (suffix || countConfig.show) {
|
||||
const dataCount = countConfig.showFormatter ? countConfig.showFormatter({
|
||||
value: formatValue,
|
||||
count: valueLength,
|
||||
maxLength: mergedMax
|
||||
}) : `${valueLength}${hasMaxLength ? ` / ${mergedMax}` : ''}`;
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, countConfig.show && /*#__PURE__*/React.createElement("span", {
|
||||
className: clsx(`${prefixCls}-show-count-suffix`, {
|
||||
[`${prefixCls}-show-count-has-suffix`]: !!suffix
|
||||
}, classNames?.count),
|
||||
style: {
|
||||
...styles?.count
|
||||
}
|
||||
}, dataCount), suffix);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// ====================== Render ======================
|
||||
return /*#__PURE__*/React.createElement(BaseInput, _extends({}, rest, {
|
||||
prefixCls: prefixCls,
|
||||
className: clsx(className, outOfRangeCls),
|
||||
handleReset: handleReset,
|
||||
value: formatValue,
|
||||
focused: focused,
|
||||
triggerFocus: focus,
|
||||
suffix: getSuffix(),
|
||||
disabled: disabled,
|
||||
classes: classes,
|
||||
classNames: classNames,
|
||||
styles: styles,
|
||||
ref: holderRef
|
||||
}), getInputElement());
|
||||
});
|
||||
export default Input;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import type { InputProps } from '..';
|
||||
import type { CountConfig, ShowCountFormatter } from '../interface';
|
||||
type ForcedCountConfig = Omit<CountConfig, 'show'> & Pick<Required<CountConfig>, 'strategy'> & {
|
||||
show: boolean;
|
||||
showFormatter?: ShowCountFormatter;
|
||||
};
|
||||
/**
|
||||
* Cut `value` by the `count.max` prop.
|
||||
*/
|
||||
export declare function inCountRange(value: string, countConfig: ForcedCountConfig): boolean;
|
||||
export default function useCount(count?: CountConfig, showCount?: InputProps['showCount']): ForcedCountConfig;
|
||||
export {};
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
import * as React from 'react';
|
||||
/**
|
||||
* Cut `value` by the `count.max` prop.
|
||||
*/
|
||||
export function inCountRange(value, countConfig) {
|
||||
if (!countConfig.max) {
|
||||
return true;
|
||||
}
|
||||
const count = countConfig.strategy(value);
|
||||
return count <= countConfig.max;
|
||||
}
|
||||
export default function useCount(count, showCount) {
|
||||
return React.useMemo(() => {
|
||||
let mergedConfig = {};
|
||||
if (showCount) {
|
||||
mergedConfig.show = typeof showCount === 'object' && showCount.formatter ? showCount.formatter : !!showCount;
|
||||
}
|
||||
mergedConfig = {
|
||||
...mergedConfig,
|
||||
...count
|
||||
};
|
||||
const {
|
||||
show,
|
||||
...rest
|
||||
} = mergedConfig;
|
||||
return {
|
||||
...rest,
|
||||
show: !!show,
|
||||
showFormatter: typeof show === 'function' ? show : undefined,
|
||||
strategy: rest.strategy || (value => value.length)
|
||||
};
|
||||
}, [count, showCount]);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import BaseInput from './BaseInput';
|
||||
import Input from './Input';
|
||||
export { BaseInput };
|
||||
export type { InputProps, InputRef } from './interface';
|
||||
export default Input;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import BaseInput from "./BaseInput";
|
||||
import Input from "./Input";
|
||||
export { BaseInput };
|
||||
export default Input;
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
import type { CSSProperties, InputHTMLAttributes, KeyboardEventHandler, MouseEventHandler, ReactElement, ReactNode } from 'react';
|
||||
import type { LiteralUnion } from './utils/types';
|
||||
import type { InputFocusOptions } from '@rc-component/util/lib/Dom/focus';
|
||||
export interface CommonInputProps {
|
||||
prefix?: ReactNode;
|
||||
suffix?: ReactNode;
|
||||
addonBefore?: ReactNode;
|
||||
addonAfter?: ReactNode;
|
||||
/** @deprecated Use `classNames` instead */
|
||||
classes?: {
|
||||
affixWrapper?: string;
|
||||
group?: string;
|
||||
wrapper?: string;
|
||||
};
|
||||
classNames?: {
|
||||
affixWrapper?: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
groupWrapper?: string;
|
||||
wrapper?: string;
|
||||
variant?: string;
|
||||
};
|
||||
styles?: {
|
||||
affixWrapper?: CSSProperties;
|
||||
prefix?: CSSProperties;
|
||||
suffix?: CSSProperties;
|
||||
};
|
||||
allowClear?: boolean | {
|
||||
clearIcon?: ReactNode;
|
||||
};
|
||||
}
|
||||
type DataAttr = Record<`data-${string}`, string>;
|
||||
export type ValueType = InputHTMLAttributes<HTMLInputElement>['value'] | bigint;
|
||||
export interface BaseInputProps extends CommonInputProps {
|
||||
value?: ValueType;
|
||||
/** @deprecated Use `children` instead */
|
||||
inputElement?: ReactElement;
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
disabled?: boolean;
|
||||
focused?: boolean;
|
||||
triggerFocus?: () => void;
|
||||
readOnly?: boolean;
|
||||
handleReset?: MouseEventHandler;
|
||||
onClear?: () => void;
|
||||
hidden?: boolean;
|
||||
dataAttrs?: {
|
||||
affixWrapper?: DataAttr;
|
||||
};
|
||||
components?: {
|
||||
affixWrapper?: 'span' | 'div';
|
||||
groupWrapper?: 'span' | 'div';
|
||||
wrapper?: 'span' | 'div';
|
||||
groupAddon?: 'span' | 'div';
|
||||
};
|
||||
children: ReactElement;
|
||||
}
|
||||
export type ShowCountFormatter = (args: {
|
||||
value: string;
|
||||
count: number;
|
||||
maxLength?: number;
|
||||
}) => ReactNode;
|
||||
export type ExceedFormatter = (value: string, config: {
|
||||
max: number;
|
||||
}) => string;
|
||||
export interface CountConfig {
|
||||
max?: number;
|
||||
strategy?: (value: string) => number;
|
||||
show?: boolean | ShowCountFormatter;
|
||||
/** Trigger when content larger than the `max` limitation */
|
||||
exceedFormatter?: ExceedFormatter;
|
||||
}
|
||||
export interface InputProps extends CommonInputProps, Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix' | 'type' | 'value'> {
|
||||
value?: ValueType;
|
||||
prefixCls?: string;
|
||||
type?: LiteralUnion<'button' | 'checkbox' | 'color' | 'date' | 'datetime-local' | 'email' | 'file' | 'hidden' | 'image' | 'month' | 'number' | 'password' | 'radio' | 'range' | 'reset' | 'search' | 'submit' | 'tel' | 'text' | 'time' | 'url' | 'week', string>;
|
||||
onPressEnter?: KeyboardEventHandler<HTMLInputElement>;
|
||||
/** It's better to use `count.show` instead */
|
||||
showCount?: boolean | {
|
||||
formatter: ShowCountFormatter;
|
||||
};
|
||||
autoComplete?: string;
|
||||
htmlSize?: number;
|
||||
classNames?: CommonInputProps['classNames'] & {
|
||||
input?: string;
|
||||
count?: string;
|
||||
};
|
||||
styles?: CommonInputProps['styles'] & {
|
||||
input?: CSSProperties;
|
||||
count?: CSSProperties;
|
||||
};
|
||||
count?: CountConfig;
|
||||
onClear?: () => void;
|
||||
}
|
||||
export interface InputRef {
|
||||
focus: (options?: InputFocusOptions) => void;
|
||||
blur: () => void;
|
||||
setSelectionRange: (start: number, end: number, direction?: 'forward' | 'backward' | 'none') => void;
|
||||
select: () => void;
|
||||
input: HTMLInputElement | null;
|
||||
nativeElement: HTMLElement | null;
|
||||
}
|
||||
export interface ChangeEventInfo {
|
||||
source: 'compositionEnd' | 'change';
|
||||
}
|
||||
export {};
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import type React from 'react';
|
||||
import type { BaseInputProps, InputProps } from '../interface';
|
||||
export declare function hasAddon(props: BaseInputProps | InputProps): boolean;
|
||||
export declare function hasPrefixSuffix(props: BaseInputProps | InputProps): boolean;
|
||||
export declare function resolveOnChange<E extends HTMLInputElement | HTMLTextAreaElement>(target: E, e: React.ChangeEvent<E> | React.MouseEvent<HTMLElement, MouseEvent> | React.CompositionEvent<HTMLElement>, onChange: undefined | ((event: React.ChangeEvent<E>) => void), targetValue?: string): void;
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
export function hasAddon(props) {
|
||||
return !!(props.addonBefore || props.addonAfter);
|
||||
}
|
||||
export function hasPrefixSuffix(props) {
|
||||
return !!(props.prefix || props.suffix || props.allowClear);
|
||||
}
|
||||
|
||||
// TODO: It's better to use `Proxy` replace the `element.value`. But we still need support IE11.
|
||||
function cloneEvent(event, target, value) {
|
||||
// A bug report filed on WebKit's Bugzilla tracker, dating back to 2009, specifically addresses the issue of cloneNode() not copying files of <input type="file"> elements.
|
||||
// As of the last update, this bug was still marked as "NEW," indicating that it might not have been resolved yet.
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=28123
|
||||
const currentTarget = target.cloneNode(true);
|
||||
|
||||
// click clear icon
|
||||
const newEvent = Object.create(event, {
|
||||
target: {
|
||||
value: currentTarget
|
||||
},
|
||||
currentTarget: {
|
||||
value: currentTarget
|
||||
}
|
||||
});
|
||||
|
||||
// Fill data
|
||||
currentTarget.value = value;
|
||||
|
||||
// Fill selection. Some type like `email` not support selection
|
||||
// https://github.com/ant-design/ant-design/issues/47833
|
||||
if (typeof target.selectionStart === 'number' && typeof target.selectionEnd === 'number') {
|
||||
currentTarget.selectionStart = target.selectionStart;
|
||||
currentTarget.selectionEnd = target.selectionEnd;
|
||||
}
|
||||
currentTarget.setSelectionRange = (...args) => {
|
||||
target.setSelectionRange(...args);
|
||||
};
|
||||
return newEvent;
|
||||
}
|
||||
export function resolveOnChange(target, e, onChange, targetValue) {
|
||||
if (!onChange) {
|
||||
return;
|
||||
}
|
||||
let event = e;
|
||||
if (e.type === 'click') {
|
||||
// Clone a new target for event.
|
||||
// Avoid the following usage, the setQuery method gets the original value.
|
||||
//
|
||||
// const [query, setQuery] = React.useState('');
|
||||
// <Input
|
||||
// allowClear
|
||||
// value={query}
|
||||
// onChange={(e)=> {
|
||||
// setQuery((prevStatus) => e.target.value);
|
||||
// }}
|
||||
// />
|
||||
|
||||
event = cloneEvent(e, target, '');
|
||||
onChange(event);
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger by composition event, this means we need force change the input value
|
||||
// https://github.com/ant-design/ant-design/issues/45737
|
||||
// https://github.com/ant-design/ant-design/issues/46598
|
||||
if (target.type !== 'file' && targetValue !== undefined) {
|
||||
event = cloneEvent(e, target, targetValue);
|
||||
onChange(event);
|
||||
return;
|
||||
}
|
||||
onChange(event);
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
/** https://github.com/Microsoft/TypeScript/issues/29729 */
|
||||
export type LiteralUnion<T extends U, U> = T | (U & Record<never, never>);
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Reference in New Issue
Block a user