Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/components/select-input/SelectInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ export interface SelectInputProps extends TdSelectInputProps, StyledProps {
options?: any[]; // 参数穿透options, 给SelectInput/SelectInput 自定义选中项呈现的内容和多选状态下设置折叠项内容
}

const SelectInput = React.forwardRef<Partial<PopupRef & InputRef>, SelectInputProps>((originalProps, ref) => {
export type SelectInputRef = Partial<PopupRef & InputRef>;

const SelectInput = React.forwardRef<SelectInputRef, SelectInputProps>((originalProps, ref) => {
const { classPrefix: prefix } = useConfig();

const props = useDefaultProps<SelectInputProps>(originalProps, selectInputDefaultProps);
Expand Down
2 changes: 1 addition & 1 deletion packages/components/select-input/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import _SelectInput from './SelectInput';

import './style/index.js';

export type { SelectInputProps } from './SelectInput';
export type { SelectInputProps, SelectInputRef } from './SelectInput';
export * from './type';

export const SelectInput = _SelectInput;
Expand Down
10 changes: 7 additions & 3 deletions packages/components/select-input/useSingle.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useRef } from 'react';
import React, { useRef, useState } from 'react';

import classNames from 'classnames';
import { isObject, pick } from 'lodash-es';
Expand Down Expand Up @@ -50,6 +50,8 @@ export default function useSingle(props: TdSelectInputProps) {
const inputRef = useRef<InputRef>(null);
const blurTimeoutRef = useRef(null);

const [isInputFocused, setIsInputFocused] = useState(false);

const [inputValue, setInputValue] = useControlled(props, 'inputValue', props.onInputChange);

const commonInputProps: SelectInputCommonProperties = {
Expand Down Expand Up @@ -84,6 +86,7 @@ export default function useSingle(props: TdSelectInputProps) {
// 强制把 popupVisible 设置为 false 时,点击 input,会出现 blur -> focus 的情况,因此忽略前面短暂的 blur 事件
blurTimeoutRef.current = setTimeout(() => {
if (blurTimeoutRef.current) {
setIsInputFocused(false);
if (!popupVisible) {
onInnerBlur(ctx);
} else if (!props.panel) {
Expand All @@ -99,6 +102,7 @@ export default function useSingle(props: TdSelectInputProps) {
clearTimeout(blurTimeoutRef.current);
blurTimeoutRef.current = null;
}
setIsInputFocused(true);
props.onFocus?.(value, { ...context, inputValue: val });
// focus might not need to change input value. it will caught some curious errors in tree-select
// !popupVisible && setInputValue(getInputValue(value, keys), { ...context, trigger: 'input' });
Expand Down Expand Up @@ -131,8 +135,8 @@ export default function useSingle(props: TdSelectInputProps) {
onBlur={handleBlur}
{...props.inputProps}
inputClass={classNames(props.inputProps?.className, {
[`${classPrefix}-input--focused`]: popupVisible,
[`${classPrefix}-is-focused`]: popupVisible,
[`${classPrefix}-input--focused`]: popupVisible || isInputFocused,
[`${classPrefix}-is-focused`]: popupVisible || isInputFocused,
})}
/>
);
Expand Down
8 changes: 5 additions & 3 deletions packages/components/select/base/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import useDefaultProps from '../../hooks/useDefaultProps';
import Loading from '../../loading';
import { useLocaleReceiver } from '../../locale/LocalReceiver';
import SelectInput, {
SelectInputChangeContext,
type SelectInputChangeContext,
type SelectInputRef,
type SelectInputValue,
type SelectInputValueChangeContext,
} from '../../select-input';
Expand All @@ -49,7 +50,7 @@ export interface SelectProps<T = SelectOption> extends TdSelectProps<T>, StyledP
type OptionsType = TdOptionProps[];

const Select = forwardRefWithStatics(
(originalProps: SelectProps, ref: React.Ref<HTMLDivElement>) => {
(originalProps: SelectProps, ref: React.Ref<SelectInputRef>) => {
const props = useDefaultProps<SelectProps>(originalProps, selectDefaultProps);
// 国际化文本初始化
const [local, t] = useLocaleReceiver('select');
Expand Down Expand Up @@ -107,7 +108,7 @@ const Select = forwardRefWithStatics(

const { valueKey, labelKey, disabledKey } = useMemo(() => getKeyMapping(keys), [keys]);

const selectInputRef = useRef(null);
const selectInputRef = useRef<SelectInputRef>(null);
const { classPrefix } = useConfig();
const { overlayClassName, onScroll, onScrollToBottom, ...restPopupProps } = popupProps || {};
const [isScrolling, toggleIsScrolling] = useState(false);
Expand Down Expand Up @@ -291,6 +292,7 @@ const Select = forwardRefWithStatics(

const { hoverIndex, handleKeyDown } = useKeyboardControl({
displayOptions: flattenedOptions as TdOptionProps[],
filterable,
keys,
innerPopupVisible,
max,
Expand Down
30 changes: 26 additions & 4 deletions packages/components/select/hooks/useKeyboardControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { useEffect, useMemo, useRef, useState } from 'react';
import useConfig from '../../hooks/useConfig';
import { getKeyMapping, getSelectValueArr } from '../util/helper';

import type { SelectInputRef } from '../../select-input/SelectInput';
import type { SelectOption, SelectValue, SelectValueChangeTrigger, TdOptionProps, TdSelectProps } from '../type';

export type useKeyboardControlType = {
max: number;
multiple: boolean;
filterable: TdSelectProps['filterable'];
keys: TdSelectProps['keys'];
value: SelectValue<SelectOption>;
valueType: TdSelectProps['valueType'];
Expand All @@ -22,13 +24,14 @@ export type useKeyboardControlType = {
handlePopupVisibleChange: (visible: boolean, ctx: { e: React.KeyboardEvent<HTMLInputElement> }) => void;
displayOptions: TdOptionProps[];
onCheckAllChange: (checkAll: boolean, e?: React.KeyboardEvent<HTMLInputElement>) => void;
selectInputRef: any;
selectInputRef: React.MutableRefObject<SelectInputRef>;
toggleIsScrolling: (isScrolling: boolean) => void;
};

export default function useKeyboardControl({
max,
multiple,
filterable,
keys,
value,
valueType,
Expand Down Expand Up @@ -93,7 +96,7 @@ export default function useKeyboardControl({
let newIndex = hoverIndex;

switch (e.code) {
case 'ArrowUp':
case 'ArrowUp': {
e.preventDefault();
if (hoverIndex === -1) newIndex = 0;
else if (hoverIndex === 0 || hoverIndex > optionsListLength - 1) newIndex = optionsListLength - 1;
Expand All @@ -104,7 +107,8 @@ export default function useKeyboardControl({
changeHoverIndex(newIndex);
handleKeyboardScroll(newIndex);
break;
case 'ArrowDown':
}
case 'ArrowDown': {
e.preventDefault();
if (hoverIndex === -1 || hoverIndex >= optionsListLength - 1) newIndex = 0;
else newIndex += 1;
Expand All @@ -114,6 +118,7 @@ export default function useKeyboardControl({
changeHoverIndex(newIndex);
handleKeyboardScroll(newIndex);
break;
}
case 'Enter': {
if (!innerPopupVisible) {
handlePopupVisibleChange(true, { e });
Expand Down Expand Up @@ -152,10 +157,27 @@ export default function useKeyboardControl({
}
break;
}
case 'Escape':
case 'Escape': {
handlePopupVisibleChange(false, { e });
changeHoverIndex(-1);
handleKeyboardScroll(0);
break;
}
case 'Backspace':
case 'Delete': {
// 单选模式的删除无意义
if (!multiple && !innerPopupVisible) {
e.preventDefault();
}
break;
}
default: {
// filterable 模式,按下其它字符,打开弹窗进入输入态
if (filterable && !innerPopupVisible && e.key.length === 1) {
handlePopupVisibleChange(true, { e });
}
break;
}
}
};

Expand Down
Loading