Skip to content

Commit

Permalink
Merge branch 'dev-bqx' of https://github.com/NJUPT-SAST/SAST-UI into …
Browse files Browse the repository at this point in the history
…dev-bqx
  • Loading branch information
BQXBQX committed Mar 26, 2024
2 parents c3d59c9 + 05c4925 commit 9af1ee1
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 10 deletions.
28 changes: 24 additions & 4 deletions packages/ui-react/lib/Select/Select.module.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
@use '../variables' as *;
@use '../_variables/color.scss' as *;
@mixin select-option {
border-radius: 5px;
cursor: pointer;
color: var(--primary-color);
}
$animation-duration: $duration-300;
.input {
input::placeholder {
transition: all $animation-duration $cubic-bezier;
color: $black-color;
}
&.hide-placeholder {
input::placeholder {
color: $gray-color;
}
}
}
.options {
position: absolute;
width: 280px;
Expand Down Expand Up @@ -41,11 +58,14 @@ $animation-duration: $duration-300;
align-items: center;
transition: all $animation-duration $cubic-bezier;
&:hover {
background-color: rgba(var(--shadow-color-rgb), 0.1);
background-color: rgba(var(--shadow-color-rgb), 0.08);
padding: 0 0 0 2px;
@include select-option();
}
&.option-item-selected {
background-color: rgba(var(--shadow-color-rgb), 0.15);
padding: 0 0 0 4px;
border-radius: 5px;
cursor: pointer;
color: var(--primary-color);
@include select-option();
}
.option-item-span {
padding: 0 7px;
Expand Down
70 changes: 64 additions & 6 deletions packages/ui-react/lib/Select/Select.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import React, { useState, type MouseEventHandler, useEffect } from 'react';
import React, {
useState,
type MouseEventHandler,
type KeyboardEvent,
useEffect,
useRef,
} from 'react';
import styles from './Select.module.scss';
import { Input } from '..';

Expand Down Expand Up @@ -66,13 +72,18 @@ export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
},
ref,
) => {
// Here selectItemIndex is different from selectItem,
// selectItem is all the contents of the selected selectItem,
// selectItemIndex is the index value inside options, starting from 0, and has nothing to do with the key inside the options.
const [visible, setVisble] = useState<boolean>(false);
const [selectItem, setSelectItem] = useState<OptionProps | undefined>(
optionsList.find((item) => item.key === defaultSelectKey),
);
const [options, setOptions] = useState<OptionProps[]>(optionsList);
const [inputValue, setInputValue] = useState<string>('');
const [selectPlaceHolder, setSelectPlaceHolder] = useState<string>('');
const [selectItemIndex, setSelectItemIndex] = useState<number>(-1);
const inputRef = useRef<HTMLInputElement>(null);

useEffect(() => {
setSelectPlaceHolder(placeHolder);
Expand All @@ -94,10 +105,48 @@ export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
}, 300);
}

const onKeyDown = (event: KeyboardEvent) => {
const optionsList = options;
const listLength = optionsList.length;
if (listLength === 0) return;
const KEY_ARROW_DOWN = 'arrowdown';
const KEY_ARROW_UP = 'arrowup';
const KEY_ENTER = 'enter';

function handleArrowDown() {
if (selectItemIndex === -1 || selectItemIndex === optionsList.length - 1) {
setSelectItemIndex(0);
} else {
setSelectItemIndex((selectItemIndex) => selectItemIndex + 1);
}
}

function handleArrowUp() {
if (selectItemIndex === -1 || selectItemIndex === 0) {
setSelectItemIndex(optionsList.length - 1);
} else {
setSelectItemIndex((selectItemIndex) => selectItemIndex - 1);
}
}

function handleEnter() {
if (selectItemIndex !== -1) {
handleClick(optionsList[selectItemIndex]!);
closeOptions();
}
}

if (event.key.toLocaleLowerCase() === KEY_ARROW_DOWN) {
handleArrowDown();
} else if (event.key.toLocaleLowerCase() === KEY_ARROW_UP) {
handleArrowUp();
} else if (event.key.toLocaleLowerCase() === KEY_ENTER) {
handleEnter();
}
};

useEffect(() => {
onchange && selectItem && onchange(selectItem);
console.log(selectItem?.label);

selectItem?.label && setSelectPlaceHolder(selectItem.label);
}, [selectItem, onchange]);

Expand All @@ -113,14 +162,17 @@ export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
return optionsList.filter((option) => regex.test(option.label));
}

// When closeoptions, you need to set selectItemIndex to -1,
// and at the same time input loses focus and options disappear.
const closeOptions = () => {
setSelectItemIndex(-1);
inputRef.current?.blur();
setTimeout(() => {
setVisble(false);
}, 100);
};

useEffect(() => {
console.log(inputValue);
const results = fuzzySearch(optionsList, inputValue);
setOptions(results);
}, [inputValue, optionsList]);
Expand All @@ -141,6 +193,12 @@ export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
isBorder={isBorder}
placeholder={selectPlaceHolder}
disabled={disabled}
onKeyDown={onKeyDown.bind(this)}
ref={inputRef}
// According to the visible of the options box, determine the color of the placeholder,
// if the options are not expanded, the display will be black,
// if it has been expanded, the display will be gray.
className={`${styles['input']} ${visible ? styles['hide-placeholder'] : ''}`}
></Input>
<div className={`${styles['options']} ${visible ? styles['show'] : ''}`}>
{!options.length ? (
Expand All @@ -149,11 +207,11 @@ export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
<span style={{ fontWeight: '700' }}>什么都没有检索到哦😭</span>
</div>
) : (
options.map((obj) => {
options.map((obj, index) => {
return (
<div
key={obj.key}
className={styles['option-item']}
className={`${styles['option-item']} ${styles['option-item']}_${obj.key} ${selectItemIndex === index ? styles['option-item-selected'] : ''}`}
onClick={() => handleClick(obj)}
>
<span className={styles['option-item-span']}>{obj.label}</span>
Expand Down

0 comments on commit 9af1ee1

Please sign in to comment.