You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
5.9 KiB

/**
* To match accessibility requirement, we always provide an input in the component.
* Other element will not set `tabIndex` to avoid `onBlur` sequence problem.
* For focused select, we set `aria-live="polite"` to update the accessibility content.
*
* ref:
* - keyboard: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role#Keyboard_interactions
*/
import * as React from 'react';
import { RenderNode, Mode, RenderDOMFunc } from './interface';
import { GetLabeledValue, FilterOptions, FilterFunc, DefaultValueType, RawValueType, LabelValueType, Key, FlattenOptionsType, SingleType, OnClear, SelectSource, CustomTagProps } from './interface/generator';
import { OptionListProps, RefOptionListProps } from './OptionList';
export interface RefSelectProps {
focus: () => void;
blur: () => void;
}
export interface SelectProps<OptionsType extends object[], ValueType> extends React.AriaAttributes {
prefixCls?: string;
id?: string;
className?: string;
style?: React.CSSProperties;
options?: OptionsType;
children?: React.ReactNode;
mode?: Mode;
value?: ValueType;
defaultValue?: ValueType;
labelInValue?: boolean;
inputValue?: string;
searchValue?: string;
optionFilterProp?: string;
/**
* In Select, `false` means do nothing.
* In TreeSelect, `false` will highlight match item.
* It's by design.
*/
filterOption?: boolean | FilterFunc<OptionsType[number]>;
showSearch?: boolean;
autoClearSearchValue?: boolean;
onSearch?: (value: string) => void;
allowClear?: boolean;
clearIcon?: React.ReactNode;
showArrow?: boolean;
inputIcon?: RenderNode;
removeIcon?: React.ReactNode;
menuItemSelectedIcon?: RenderNode;
open?: boolean;
defaultOpen?: boolean;
listHeight?: number;
listItemHeight?: number;
dropdownStyle?: React.CSSProperties;
dropdownClassName?: string;
dropdownMatchSelectWidth?: boolean | number;
virtual?: boolean;
dropdownRender?: (menu: React.ReactElement) => React.ReactElement;
dropdownAlign?: any;
animation?: string;
transitionName?: string;
getPopupContainer?: RenderDOMFunc;
direction?: string;
disabled?: boolean;
loading?: boolean;
autoFocus?: boolean;
defaultActiveFirstOption?: boolean;
notFoundContent?: React.ReactNode;
placeholder?: React.ReactNode;
backfill?: boolean;
getInputElement?: () => JSX.Element;
optionLabelProp?: string;
maxTagTextLength?: number;
maxTagCount?: number;
maxTagPlaceholder?: React.ReactNode | ((omittedValues: LabelValueType[]) => React.ReactNode);
tokenSeparators?: string[];
tagRender?: (props: CustomTagProps) => React.ReactElement;
showAction?: ('focus' | 'click')[];
tabIndex?: number;
onKeyUp?: React.KeyboardEventHandler<HTMLDivElement>;
onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
onPopupScroll?: React.UIEventHandler<HTMLDivElement>;
onDropdownVisibleChange?: (open: boolean) => void;
onSelect?: (value: SingleType<ValueType>, option: OptionsType[number]) => void;
onDeselect?: (value: SingleType<ValueType>, option: OptionsType[number]) => void;
onInputKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;
onClick?: React.MouseEventHandler;
onChange?: (value: ValueType, option: OptionsType[number] | OptionsType) => void;
onBlur?: React.FocusEventHandler<HTMLElement>;
onFocus?: React.FocusEventHandler<HTMLElement>;
onMouseDown?: React.MouseEventHandler<HTMLDivElement>;
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
choiceTransitionName?: string;
/**
* Only used in current version for internal event process.
* Do not use in production environment.
*/
internalProps?: {
mark?: string;
onClear?: OnClear;
skipTriggerChange?: boolean;
skipTriggerSelect?: boolean;
onRawSelect?: (value: RawValueType, option: OptionsType[number], source: SelectSource) => void;
onRawDeselect?: (value: RawValueType, option: OptionsType[number], source: SelectSource) => void;
};
}
export interface GenerateConfig<OptionsType extends object[]> {
prefixCls: string;
components: {
optionList: React.ForwardRefExoticComponent<React.PropsWithoutRef<Omit<OptionListProps<OptionsType>, 'options'> & {
options: OptionsType;
}> & React.RefAttributes<RefOptionListProps>>;
};
/** Convert jsx tree into `OptionsType` */
convertChildrenToData: (children: React.ReactNode) => OptionsType;
/** Flatten nest options into raw option list */
flattenOptions: (options: OptionsType, props: any) => FlattenOptionsType<OptionsType>;
/** Convert single raw value into { label, value } format. Will be called by each value */
getLabeledValue: GetLabeledValue<FlattenOptionsType<OptionsType>>;
filterOptions: FilterOptions<OptionsType>;
findValueOption: ((values: RawValueType[], options: FlattenOptionsType<OptionsType>) => OptionsType) | ((values: RawValueType[], options: FlattenOptionsType<OptionsType>, info?: {
prevValueOptions?: OptionsType[];
}) => OptionsType);
/** Check if a value is disabled */
isValueDisabled: (value: RawValueType, options: FlattenOptionsType<OptionsType>) => boolean;
warningProps?: (props: any) => void;
fillOptionsWithMissingValue?: (options: OptionsType, value: DefaultValueType, optionLabelProp: string, labelInValue: boolean) => OptionsType;
omitDOMProps?: (props: object) => object;
}
/**
* This function is in internal usage.
* Do not use it in your prod env since we may refactor this.
*/
export default function generateSelector<OptionsType extends {
value?: RawValueType;
label?: React.ReactNode;
key?: Key;
disabled?: boolean;
}[]>(config: GenerateConfig<OptionsType>): React.ForwardRefExoticComponent<SelectProps<OptionsType, DefaultValueType> & React.RefAttributes<RefSelectProps>>;