mirror of
https://github.com/ant-design/ant-design.git
synced 2025-07-31 20:36:35 +08:00

Because {element} is a child of <InputElement>, we get a circular reference when also adding "element.props" to <InputElement>, as <InputElement> will be cloned to <{element}> within InputElement.tsx. As a consequence, we get an infinitive circular loop of Element->Props->Children->Element->Props->Children->Element->Props->Children->… React seems to detect and automatically fix this infinitive loop. But when using the smaller and faster Inferno as a replacement library of React, we get a "RangeError: Maximum call stack size exceeded". This commit fixes this bug by not attaching {...element.props} to <InputElement>. All tests did pass and I did not notice any changes in the behaviour of the AutoComplete component. But now, AutoComplete works also with Inferno and not only with React.
112 lines
3.3 KiB
TypeScript
Executable File
112 lines
3.3 KiB
TypeScript
Executable File
import React from 'react';
|
|
import { Option, OptGroup } from 'rc-select';
|
|
import classNames from 'classnames';
|
|
import Select, { AbstractSelectProps, SelectValue, OptionProps, OptGroupProps } from '../select';
|
|
import Input from '../input';
|
|
import InputElement from './InputElement';
|
|
|
|
export interface DataSourceItemObject { value: string; text: string; }
|
|
export type DataSourceItemType = string | DataSourceItemObject;
|
|
|
|
export interface InputProps {
|
|
onChange?: React.FormEventHandler<any>;
|
|
value: any;
|
|
}
|
|
|
|
export type ValidInputElement =
|
|
HTMLInputElement |
|
|
HTMLTextAreaElement |
|
|
React.ReactElement<InputProps>;
|
|
|
|
export interface AutoCompleteProps extends AbstractSelectProps {
|
|
value?: SelectValue;
|
|
defaultValue?: SelectValue;
|
|
dataSource: DataSourceItemType[];
|
|
optionLabelProp?: string;
|
|
onChange?: (value: SelectValue) => void;
|
|
onSelect?: (value: SelectValue, option: Object) => any;
|
|
children?: ValidInputElement |
|
|
React.ReactElement<OptionProps> |
|
|
Array<React.ReactElement<OptionProps>>;
|
|
}
|
|
|
|
function isSelectOptionOrSelectOptGroup(child: any): Boolean {
|
|
return child && child.type && (child.type.isSelectOption || child.type.isSelectOptGroup);
|
|
}
|
|
|
|
export default class AutoComplete extends React.Component<AutoCompleteProps, any> {
|
|
static Option = Option as React.ClassicComponentClass<OptionProps>;
|
|
static OptGroup = OptGroup as React.ClassicComponentClass<OptGroupProps>;
|
|
|
|
static defaultProps = {
|
|
prefixCls: 'ant-select',
|
|
transitionName: 'slide-up',
|
|
optionLabelProp: 'children',
|
|
choiceTransitionName: 'zoom',
|
|
showSearch: false,
|
|
filterOption: false,
|
|
};
|
|
|
|
getInputElement = () => {
|
|
const { children } = this.props;
|
|
const element = children && React.isValidElement(children) && children.type !== Option ?
|
|
React.Children.only(this.props.children) : <Input />;
|
|
return (
|
|
<InputElement>{element}</InputElement>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
let {
|
|
size, className = '', notFoundContent, prefixCls, optionLabelProp, dataSource, children,
|
|
} = this.props;
|
|
|
|
const cls = classNames({
|
|
[`${prefixCls}-lg`]: size === 'large',
|
|
[`${prefixCls}-sm`]: size === 'small',
|
|
[className]: !!className,
|
|
[`${prefixCls}-show-search`]: true,
|
|
[`${prefixCls}-auto-complete`]: true,
|
|
});
|
|
|
|
let options;
|
|
const childArray = React.Children.toArray(children);
|
|
if (childArray.length &&
|
|
isSelectOptionOrSelectOptGroup(childArray[0])
|
|
) {
|
|
options = children;
|
|
} else {
|
|
options = dataSource ? dataSource.map((item) => {
|
|
if (React.isValidElement(item)) {
|
|
return item;
|
|
}
|
|
switch (typeof item) {
|
|
case 'string':
|
|
return <Option key={item}>{item}</Option>;
|
|
case 'object':
|
|
return (
|
|
<Option key={(item as DataSourceItemObject).value}>
|
|
{(item as DataSourceItemObject).text}
|
|
</Option>
|
|
);
|
|
default:
|
|
throw new Error('AutoComplete[dataSource] only supports type `string[] | Object[]`.');
|
|
}
|
|
}) : [];
|
|
}
|
|
|
|
return (
|
|
<Select
|
|
{...this.props}
|
|
className={cls}
|
|
mode="combobox"
|
|
optionLabelProp={optionLabelProp}
|
|
getInputElement={this.getInputElement}
|
|
notFoundContent={notFoundContent}
|
|
>
|
|
{options}
|
|
</Select>
|
|
);
|
|
}
|
|
}
|