2023-07-15 12:57:03 +08:00
|
|
|
'use client';
|
2019-09-12 20:15:17 +08:00
|
|
|
|
2016-07-25 17:46:45 +08:00
|
|
|
import classNames from 'classnames';
|
2021-12-21 21:38:11 +08:00
|
|
|
import type { BaseSelectRef } from 'rc-select';
|
2022-06-22 14:57:09 +08:00
|
|
|
import toArray from 'rc-util/lib/Children/toArray';
|
|
|
|
import omit from 'rc-util/lib/omit';
|
2023-05-06 15:49:37 +08:00
|
|
|
import * as React from 'react';
|
2023-04-04 17:17:36 +08:00
|
|
|
import genPurePanel from '../_util/PurePanel';
|
|
|
|
import { isValidElement } from '../_util/reactNode';
|
|
|
|
import type { InputStatus } from '../_util/statusUtils';
|
|
|
|
import warning from '../_util/warning';
|
2022-06-22 14:57:09 +08:00
|
|
|
import type { ConfigConsumerProps } from '../config-provider';
|
2022-12-25 18:34:42 +08:00
|
|
|
import { ConfigContext } from '../config-provider';
|
2022-05-07 14:31:54 +08:00
|
|
|
import type {
|
2021-12-21 21:38:11 +08:00
|
|
|
BaseOptionType,
|
|
|
|
DefaultOptionType,
|
|
|
|
InternalSelectProps,
|
|
|
|
RefSelectProps,
|
|
|
|
} from '../select';
|
2022-05-07 14:31:54 +08:00
|
|
|
import Select from '../select';
|
2019-09-12 20:15:17 +08:00
|
|
|
|
|
|
|
const { Option } = Select;
|
|
|
|
|
2018-12-07 20:02:01 +08:00
|
|
|
export interface DataSourceItemObject {
|
|
|
|
value: string;
|
|
|
|
text: string;
|
|
|
|
}
|
2020-11-20 10:11:58 +08:00
|
|
|
export type DataSourceItemType = DataSourceItemObject | React.ReactNode;
|
2017-01-13 21:19:23 +08:00
|
|
|
|
2021-12-21 21:38:11 +08:00
|
|
|
export interface AutoCompleteProps<
|
|
|
|
ValueType = any,
|
|
|
|
OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType,
|
|
|
|
> extends Omit<
|
|
|
|
InternalSelectProps<ValueType, OptionType>,
|
2020-05-14 15:57:04 +08:00
|
|
|
'inputIcon' | 'loading' | 'mode' | 'optionLabelProp' | 'labelInValue'
|
|
|
|
> {
|
2018-04-16 17:42:31 +08:00
|
|
|
dataSource?: DataSourceItemType[];
|
2022-02-17 16:41:24 +08:00
|
|
|
status?: InputStatus;
|
2022-08-05 11:21:07 +08:00
|
|
|
popupClassName?: string;
|
2022-09-08 14:33:11 +08:00
|
|
|
/** @deprecated Please use `popupClassName` instead */
|
|
|
|
dropdownClassName?: string;
|
2023-04-04 17:17:36 +08:00
|
|
|
/** @deprecated Please use `popupMatchSelectWidth` instead */
|
|
|
|
dropdownMatchSelectWidth?: boolean | number;
|
|
|
|
popupMatchSelectWidth?: boolean | number;
|
2017-01-13 21:19:23 +08:00
|
|
|
}
|
|
|
|
|
2017-03-03 22:10:21 +08:00
|
|
|
function isSelectOptionOrSelectOptGroup(child: any): Boolean {
|
|
|
|
return child && child.type && (child.type.isSelectOption || child.type.isSelectOptGroup);
|
|
|
|
}
|
|
|
|
|
2020-11-03 11:09:24 +08:00
|
|
|
const AutoComplete: React.ForwardRefRenderFunction<RefSelectProps, AutoCompleteProps> = (
|
2020-10-24 20:33:18 +08:00
|
|
|
props,
|
|
|
|
ref,
|
|
|
|
) => {
|
2022-09-08 14:33:11 +08:00
|
|
|
const {
|
|
|
|
prefixCls: customizePrefixCls,
|
|
|
|
className,
|
|
|
|
popupClassName,
|
|
|
|
dropdownClassName,
|
|
|
|
children,
|
|
|
|
dataSource,
|
|
|
|
} = props;
|
2019-09-12 20:15:17 +08:00
|
|
|
const childNodes: React.ReactElement[] = toArray(children);
|
|
|
|
|
|
|
|
// ============================= Input =============================
|
2020-09-16 11:51:55 +08:00
|
|
|
let customizeInput: React.ReactElement | undefined;
|
2019-09-12 20:15:17 +08:00
|
|
|
|
|
|
|
if (
|
|
|
|
childNodes.length === 1 &&
|
2020-05-14 20:54:49 +08:00
|
|
|
isValidElement(childNodes[0]) &&
|
2019-09-12 20:15:17 +08:00
|
|
|
!isSelectOptionOrSelectOptGroup(childNodes[0])
|
|
|
|
) {
|
2020-06-08 18:01:50 +08:00
|
|
|
[customizeInput] = childNodes;
|
2017-11-19 01:41:40 +08:00
|
|
|
}
|
|
|
|
|
2020-09-16 11:51:55 +08:00
|
|
|
const getInputElement = customizeInput ? (): React.ReactElement => customizeInput! : undefined;
|
2019-09-12 20:15:17 +08:00
|
|
|
|
|
|
|
// ============================ Options ============================
|
|
|
|
let optionChildren: React.ReactNode;
|
|
|
|
|
|
|
|
// [Legacy] convert `children` or `dataSource` into option children
|
|
|
|
if (childNodes.length && isSelectOptionOrSelectOptGroup(childNodes[0])) {
|
|
|
|
optionChildren = children;
|
|
|
|
} else {
|
|
|
|
optionChildren = dataSource
|
2022-11-19 13:47:33 +08:00
|
|
|
? dataSource.map((item) => {
|
2020-05-14 20:54:49 +08:00
|
|
|
if (isValidElement(item)) {
|
2019-09-12 20:15:17 +08:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
switch (typeof item) {
|
|
|
|
case 'string':
|
|
|
|
return (
|
2019-11-06 11:18:11 +08:00
|
|
|
<Option key={item} value={item}>
|
|
|
|
{item}
|
|
|
|
</Option>
|
|
|
|
);
|
|
|
|
case 'object': {
|
|
|
|
const { value: optionValue } = item as DataSourceItemObject;
|
|
|
|
return (
|
|
|
|
<Option key={optionValue} value={optionValue}>
|
2019-09-12 20:15:17 +08:00
|
|
|
{(item as DataSourceItemObject).text}
|
|
|
|
</Option>
|
|
|
|
);
|
2019-11-06 11:18:11 +08:00
|
|
|
}
|
2019-09-12 20:15:17 +08:00
|
|
|
default:
|
2022-05-10 15:43:29 +08:00
|
|
|
warning(
|
|
|
|
false,
|
|
|
|
'AutoComplete',
|
|
|
|
'`dataSource` is only supports type `string[] | Object[]`.',
|
|
|
|
);
|
|
|
|
return undefined;
|
2019-09-12 20:15:17 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
: [];
|
2017-11-19 01:41:40 +08:00
|
|
|
}
|
|
|
|
|
2022-09-08 14:33:11 +08:00
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
|
|
warning(
|
|
|
|
!('dataSource' in props),
|
|
|
|
'AutoComplete',
|
|
|
|
'`dataSource` is deprecated, please use `options` instead.',
|
|
|
|
);
|
2018-12-05 19:12:18 +08:00
|
|
|
|
2022-09-08 14:33:11 +08:00
|
|
|
warning(
|
|
|
|
!customizeInput || !('size' in props),
|
|
|
|
'AutoComplete',
|
|
|
|
'You need to control style self instead of setting `size` when using customize input.',
|
|
|
|
);
|
|
|
|
|
|
|
|
warning(
|
|
|
|
!dropdownClassName,
|
|
|
|
'AutoComplete',
|
|
|
|
'`dropdownClassName` is deprecated, please use `popupClassName` instead.',
|
|
|
|
);
|
|
|
|
}
|
2019-09-12 20:15:17 +08:00
|
|
|
|
2022-12-25 18:34:42 +08:00
|
|
|
const { getPrefixCls } = React.useContext<ConfigConsumerProps>(ConfigContext);
|
|
|
|
|
|
|
|
const prefixCls = getPrefixCls('select', customizePrefixCls);
|
|
|
|
|
2019-09-12 20:15:17 +08:00
|
|
|
return (
|
2022-12-25 18:34:42 +08:00
|
|
|
<Select
|
|
|
|
ref={ref}
|
2023-03-05 23:29:03 +08:00
|
|
|
showArrow={false}
|
2022-12-25 18:34:42 +08:00
|
|
|
{...omit(props, ['dataSource', 'dropdownClassName'])}
|
|
|
|
prefixCls={prefixCls}
|
|
|
|
popupClassName={popupClassName || dropdownClassName}
|
|
|
|
className={classNames(`${prefixCls}-auto-complete`, className)}
|
|
|
|
mode={Select.SECRET_COMBOBOX_MODE_DO_NOT_USE as any}
|
|
|
|
{...{
|
|
|
|
// Internal api
|
|
|
|
getInputElement,
|
2019-09-12 20:15:17 +08:00
|
|
|
}}
|
2022-12-25 18:34:42 +08:00
|
|
|
>
|
|
|
|
{optionChildren}
|
|
|
|
</Select>
|
2019-09-12 20:15:17 +08:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2021-12-21 21:38:11 +08:00
|
|
|
const RefAutoComplete = React.forwardRef<RefSelectProps, AutoCompleteProps>(
|
|
|
|
AutoComplete,
|
|
|
|
) as unknown as (<
|
|
|
|
ValueType = any,
|
|
|
|
OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType,
|
|
|
|
>(
|
|
|
|
props: React.PropsWithChildren<AutoCompleteProps<ValueType, OptionType>> & {
|
|
|
|
ref?: React.Ref<BaseSelectRef>;
|
|
|
|
},
|
|
|
|
) => React.ReactElement) & {
|
|
|
|
Option: typeof Option;
|
2022-08-25 11:50:24 +08:00
|
|
|
_InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel;
|
2019-09-12 20:15:17 +08:00
|
|
|
};
|
|
|
|
|
2022-08-25 11:50:24 +08:00
|
|
|
// We don't care debug panel
|
2023-06-07 21:59:21 +08:00
|
|
|
/* istanbul ignore next */
|
2022-08-25 11:50:24 +08:00
|
|
|
const PurePanel = genPurePanel(RefAutoComplete);
|
|
|
|
|
2021-12-21 21:38:11 +08:00
|
|
|
RefAutoComplete.Option = Option;
|
2022-08-25 11:50:24 +08:00
|
|
|
RefAutoComplete._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
2019-09-12 20:15:17 +08:00
|
|
|
|
2023-01-08 21:30:41 +08:00
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
|
|
AutoComplete.displayName = 'AutoComplete';
|
|
|
|
}
|
|
|
|
|
2021-12-21 21:38:11 +08:00
|
|
|
export default RefAutoComplete;
|