mirror of https://github.com/halo-dev/halo
pref: improve hover and pre-selection state for formkit select (#6607)
#### What type of PR is this? /kind improvement /area ui /milestone 2.20.x #### What this PR does / why we need it: 优化了 Formkit 中的 selec 组件,使得其使用快捷键与鼠标选中的预选状态始终只有一个。且在多选状态下按回车时,不再预选跳转至第一个选项。 #### How to test it? 在多选状态下测试使用键盘进行预选及使用鼠标 hover 进行预选的状态是否符合预期。 #### Which issue(s) this PR fixes: Fixes #6600 #### Does this PR introduce a user-facing change? ```release-note 优化 Formkit select 组件在多选状态下的待选中状态。 ```pull/6651/head
parent
7ed859cefb
commit
25eec1ec4f
|
@ -27,6 +27,8 @@ const emit = defineEmits<{
|
|||
|
||||
const selectedIndex = ref<number>(0);
|
||||
const selectOptionRef = ref<HTMLElement>();
|
||||
const oldEvent = ref<MouseEvent | undefined>();
|
||||
const isCursorHidden = ref(false);
|
||||
|
||||
const selectedValues = computed(() =>
|
||||
props.selectedOptions?.map((option) => option.value)
|
||||
|
@ -46,6 +48,9 @@ const getSelectedIndex = () => {
|
|||
};
|
||||
|
||||
const handleKeydown = (event: KeyboardEvent) => {
|
||||
if (selectOptionRef.value) {
|
||||
isCursorHidden.value = true;
|
||||
}
|
||||
const key = event.key;
|
||||
if (key === "ArrowUp") {
|
||||
selectedIndex.value =
|
||||
|
@ -138,7 +143,7 @@ const handleOptionScroll = (state: UseScrollReturn) => {
|
|||
};
|
||||
|
||||
watch(
|
||||
() => props.options,
|
||||
props.options,
|
||||
() => {
|
||||
selectedIndex.value = getSelectedIndex();
|
||||
},
|
||||
|
@ -153,6 +158,48 @@ watch(
|
|||
handleScrollIntoView();
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* check if cursor is changed
|
||||
*
|
||||
* @param newEvent
|
||||
* @param oldEvent
|
||||
*/
|
||||
const isCursorChanged = (
|
||||
newEvent: MouseEvent,
|
||||
oldEvent: MouseEvent | undefined
|
||||
) => {
|
||||
if (!oldEvent) {
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
newEvent.screenX !== oldEvent.screenX ||
|
||||
newEvent.screenY !== oldEvent.screenY
|
||||
);
|
||||
};
|
||||
|
||||
const handleMouseover = (event: MouseEvent) => {
|
||||
if (isCursorHidden.value) {
|
||||
if (!oldEvent.value) {
|
||||
oldEvent.value = event;
|
||||
}
|
||||
|
||||
if (isCursorChanged(event, oldEvent.value)) {
|
||||
isCursorHidden.value = false;
|
||||
oldEvent.value = undefined;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const target = event.target as HTMLElement;
|
||||
if (
|
||||
target.classList.contains("select-option-item") &&
|
||||
target instanceof HTMLElement
|
||||
) {
|
||||
const parentElement = target.parentElement as HTMLElement;
|
||||
const index = Array.from(parentElement.children).indexOf(target);
|
||||
selectedIndex.value = index;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -160,17 +207,18 @@ watch(
|
|||
id="select-option"
|
||||
ref="selectOptionRef"
|
||||
v-scroll="[handleOptionScroll, { throttle: 10 }]"
|
||||
class="select max-h-64 cursor-pointer overflow-y-auto p-1.5"
|
||||
class="select max-h-64 overflow-y-auto p-1.5"
|
||||
:class="[isCursorHidden ? 'cursor-none' : 'cursor-pointer']"
|
||||
role="list"
|
||||
tabindex="-1"
|
||||
@keydown="handleKeydown"
|
||||
@mouseover="handleMouseover"
|
||||
>
|
||||
<template v-for="(option, index) in options" :key="option.value">
|
||||
<SelectOptionItem
|
||||
class="select-option-item"
|
||||
:option="option"
|
||||
:class="{
|
||||
'hover:bg-zinc-100': !isDisabled(option),
|
||||
'bg-zinc-100': !isDisabled(option) && selectedIndex === index,
|
||||
'selected !bg-zinc-200/60':
|
||||
selectedValues && selectedValues.includes(option.value),
|
||||
|
|
Loading…
Reference in New Issue