fix: select keyboard position error
parent
656d14fc4e
commit
604372ff2d
|
@ -0,0 +1,16 @@
|
||||||
|
import { Ref, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
export default function useMemo<T>(
|
||||||
|
getValue: () => T,
|
||||||
|
condition: any[],
|
||||||
|
shouldUpdate: (prev: any[], next: any[]) => boolean,
|
||||||
|
) {
|
||||||
|
const cacheRef: Ref<T> = ref(getValue() as any);
|
||||||
|
watch(condition, (pre, next) => {
|
||||||
|
if (shouldUpdate(pre, next)) {
|
||||||
|
cacheRef.value = getValue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return cacheRef;
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import {
|
||||||
OnActiveValue,
|
OnActiveValue,
|
||||||
} from './interface';
|
} from './interface';
|
||||||
import { RawValueType, FlattenOptionsType } from './interface/generator';
|
import { RawValueType, FlattenOptionsType } from './interface/generator';
|
||||||
|
import useMemo from '../_util/hooks/useMemo';
|
||||||
export interface OptionListProps {
|
export interface OptionListProps {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -78,6 +79,12 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const itemPrefixCls = computed(() => `${props.prefixCls}-item`);
|
const itemPrefixCls = computed(() => `${props.prefixCls}-item`);
|
||||||
|
|
||||||
|
const memoFlattenOptions = useMemo(
|
||||||
|
() => props.flattenOptions,
|
||||||
|
[() => props.open, () => props.flattenOptions],
|
||||||
|
(prev, next) => next[0] && prev[1] !== next[1],
|
||||||
|
);
|
||||||
|
|
||||||
// =========================== List ===========================
|
// =========================== List ===========================
|
||||||
const listRef = createRef();
|
const listRef = createRef();
|
||||||
|
|
||||||
|
@ -93,12 +100,12 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
|
|
||||||
// ========================== Active ==========================
|
// ========================== Active ==========================
|
||||||
const getEnabledActiveIndex = (index: number, offset = 1) => {
|
const getEnabledActiveIndex = (index: number, offset = 1) => {
|
||||||
const len = props.flattenOptions.length;
|
const len = memoFlattenOptions.value.length;
|
||||||
|
|
||||||
for (let i = 0; i < len; i += 1) {
|
for (let i = 0; i < len; i += 1) {
|
||||||
const current = (index + i * offset + len) % len;
|
const current = (index + i * offset + len) % len;
|
||||||
|
|
||||||
const { group, data } = props.flattenOptions[current];
|
const { group, data } = memoFlattenOptions.value[current];
|
||||||
if (!group && !(data as OptionData).disabled) {
|
if (!group && !(data as OptionData).disabled) {
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +122,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
const info = { source: fromKeyboard ? ('keyboard' as const) : ('mouse' as const) };
|
const info = { source: fromKeyboard ? ('keyboard' as const) : ('mouse' as const) };
|
||||||
|
|
||||||
// Trigger active event
|
// Trigger active event
|
||||||
const flattenItem = props.flattenOptions[index];
|
const flattenItem = memoFlattenOptions.value[index];
|
||||||
if (!flattenItem) {
|
if (!flattenItem) {
|
||||||
props.onActiveValue(null, -1, info);
|
props.onActiveValue(null, -1, info);
|
||||||
return;
|
return;
|
||||||
|
@ -127,7 +134,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
// Auto active first item when list length or searchValue changed
|
// Auto active first item when list length or searchValue changed
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
computed(() => [props.flattenOptions.length, props.searchValue]),
|
[() => memoFlattenOptions.value.length, () => props.searchValue],
|
||||||
() => {
|
() => {
|
||||||
setActive(props.defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1);
|
setActive(props.defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1);
|
||||||
},
|
},
|
||||||
|
@ -136,11 +143,11 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
// Auto scroll to item position in single mode
|
// Auto scroll to item position in single mode
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
computed(() => props.open),
|
() => props.open,
|
||||||
() => {
|
() => {
|
||||||
if (!props.multiple && props.open && props.values.size === 1) {
|
if (!props.multiple && props.open && props.values.size === 1) {
|
||||||
const value = Array.from(props.values)[0];
|
const value = Array.from(props.values)[0];
|
||||||
const index = props.flattenOptions.findIndex(({ data }) => data.value === value);
|
const index = memoFlattenOptions.value.findIndex(({ data }) => data.value === value);
|
||||||
setActive(index);
|
setActive(index);
|
||||||
scrollIntoView(index);
|
scrollIntoView(index);
|
||||||
}
|
}
|
||||||
|
@ -167,7 +174,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderItem(index: number) {
|
function renderItem(index: number) {
|
||||||
const item = props.flattenOptions[index];
|
const item = memoFlattenOptions.value[index];
|
||||||
if (!item) return null;
|
if (!item) return null;
|
||||||
|
|
||||||
const itemData = (item.data || {}) as OptionData;
|
const itemData = (item.data || {}) as OptionData;
|
||||||
|
@ -188,6 +195,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
) : null;
|
) : null;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
memoFlattenOptions,
|
||||||
renderItem,
|
renderItem,
|
||||||
listRef,
|
listRef,
|
||||||
state,
|
state,
|
||||||
|
@ -220,7 +228,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
// >>> Select
|
// >>> Select
|
||||||
case KeyCode.ENTER: {
|
case KeyCode.ENTER: {
|
||||||
// value
|
// value
|
||||||
const item = props.flattenOptions[state.activeIndex];
|
const item = memoFlattenOptions.value[state.activeIndex];
|
||||||
if (item && !item.data.disabled) {
|
if (item && !item.data.disabled) {
|
||||||
onSelectValue(item.data.value);
|
onSelectValue(item.data.value);
|
||||||
} else {
|
} else {
|
||||||
|
@ -258,6 +266,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
itemPrefixCls,
|
itemPrefixCls,
|
||||||
setActive,
|
setActive,
|
||||||
onSelectValue,
|
onSelectValue,
|
||||||
|
memoFlattenOptions,
|
||||||
} = this as any;
|
} = this as any;
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
|
@ -265,7 +274,6 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
values,
|
values,
|
||||||
height,
|
height,
|
||||||
itemHeight,
|
itemHeight,
|
||||||
flattenOptions,
|
|
||||||
menuItemSelectedIcon,
|
menuItemSelectedIcon,
|
||||||
notFoundContent,
|
notFoundContent,
|
||||||
virtual,
|
virtual,
|
||||||
|
@ -274,7 +282,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
} = this.$props as OptionListProps;
|
} = this.$props as OptionListProps;
|
||||||
const { activeIndex } = this.state;
|
const { activeIndex } = this.state;
|
||||||
// ========================== Render ==========================
|
// ========================== Render ==========================
|
||||||
if (flattenOptions.length === 0) {
|
if (memoFlattenOptions.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
role="listbox"
|
role="listbox"
|
||||||
|
@ -296,7 +304,7 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
||||||
<List
|
<List
|
||||||
itemKey="key"
|
itemKey="key"
|
||||||
ref={listRef}
|
ref={listRef}
|
||||||
data={flattenOptions}
|
data={memoFlattenOptions}
|
||||||
height={height}
|
height={height}
|
||||||
itemHeight={itemHeight}
|
itemHeight={itemHeight}
|
||||||
fullHeight={false}
|
fullHeight={false}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
import PropTypes from '../../_util/vue-types';
|
import PropTypes from '../../_util/vue-types';
|
||||||
import { RefObject } from '../../_util/createRef';
|
import { RefObject } from '../../_util/createRef';
|
||||||
import antInput from '../../_util/antInputDirective';
|
import antInput from '../../_util/antInputDirective';
|
||||||
import classNames from 'ant-design-vue/es/_util/classNames';
|
import classNames from '../../_util/classNames';
|
||||||
|
|
||||||
interface InputProps {
|
interface InputProps {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
|
|
|
@ -50,7 +50,7 @@ const SingleSelector = defineComponent<SelectorProps>({
|
||||||
return inputValue;
|
return inputValue;
|
||||||
});
|
});
|
||||||
watch(
|
watch(
|
||||||
computed(() => [combobox.value, props.activeValue]),
|
[combobox, () => props.activeValue],
|
||||||
() => {
|
() => {
|
||||||
if (combobox.value) {
|
if (combobox.value) {
|
||||||
inputChanged.value = false;
|
inputChanged.value = false;
|
||||||
|
|
|
@ -397,9 +397,9 @@ export default function generateSelector<
|
||||||
// ============================== Ref ===============================
|
// ============================== Ref ===============================
|
||||||
const selectorDomRef = createRef();
|
const selectorDomRef = createRef();
|
||||||
|
|
||||||
const mergedValue = ref(undefined);
|
const mergedValue = ref();
|
||||||
watch(
|
watch(
|
||||||
computed(() => [props.value, props.defaultValue]),
|
() => props.value,
|
||||||
() => {
|
() => {
|
||||||
mergedValue.value = props.value !== undefined ? props.value : props.defaultValue;
|
mergedValue.value = props.value !== undefined ? props.value : props.defaultValue;
|
||||||
},
|
},
|
||||||
|
@ -801,7 +801,7 @@ export default function generateSelector<
|
||||||
// Close dropdown when disabled change
|
// Close dropdown when disabled change
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
computed(() => props.disabled),
|
() => props.disabled,
|
||||||
() => {
|
() => {
|
||||||
if (innerOpen.value && !!props.disabled) {
|
if (innerOpen.value && !!props.disabled) {
|
||||||
setInnerOpen(false);
|
setInnerOpen(false);
|
||||||
|
@ -1355,7 +1355,6 @@ export default function generateSelector<
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Select.inheritAttrs = false;
|
|
||||||
Select.props = initDefaultProps(BaseProps(), {});
|
Select.props = initDefaultProps(BaseProps(), {});
|
||||||
return Select;
|
return Select;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue