fix: clarify signature reporting status
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import type { SelectHTMLAttributes } from 'react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { ChevronDown } from 'lucide-react';
|
||||
import { ChevronDown, Search } from 'lucide-react';
|
||||
|
||||
export type SelectOption = {
|
||||
label: string;
|
||||
@@ -20,6 +20,8 @@ type SelectProps = NativeSelectProps & {
|
||||
value?: string;
|
||||
defaultValue?: string;
|
||||
placeholder?: string;
|
||||
searchable?: boolean;
|
||||
searchPlaceholder?: string;
|
||||
onChange?: (event: { target: { value: string } }) => void;
|
||||
};
|
||||
|
||||
@@ -35,23 +37,33 @@ export function Select({
|
||||
onChange,
|
||||
disabled,
|
||||
placeholder,
|
||||
searchable,
|
||||
searchPlaceholder,
|
||||
required,
|
||||
...props
|
||||
}: SelectProps) {
|
||||
const selectId = id ?? props.name;
|
||||
const rootRef = useRef<HTMLLabelElement | null>(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [searchKeyword, setSearchKeyword] = useState('');
|
||||
const [internalValue, setInternalValue] = useState(defaultValue ?? value ?? options[0]?.value ?? '');
|
||||
const selectedValue = value ?? internalValue;
|
||||
const selectedOption = useMemo(
|
||||
() => options.find((option) => option.value === selectedValue),
|
||||
[options, selectedValue],
|
||||
);
|
||||
const searchEnabled = searchable ?? (typeof label === 'string' && (label.includes('企业') || label.includes('应用')));
|
||||
const visibleOptions = useMemo(() => {
|
||||
const normalizedKeyword = searchKeyword.trim().toLocaleLowerCase();
|
||||
if (!searchEnabled || !normalizedKeyword) return options;
|
||||
return options.filter((option) => option.label.toLocaleLowerCase().includes(normalizedKeyword));
|
||||
}, [options, searchEnabled, searchKeyword]);
|
||||
|
||||
useEffect(() => {
|
||||
function handlePointerDown(event: PointerEvent) {
|
||||
if (rootRef.current && !rootRef.current.contains(event.target as Node)) {
|
||||
setOpen(false);
|
||||
setSearchKeyword('');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +75,7 @@ export function Select({
|
||||
setInternalValue(nextValue);
|
||||
onChange?.({ target: { value: nextValue } });
|
||||
setOpen(false);
|
||||
setSearchKeyword('');
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -90,7 +103,10 @@ export function Select({
|
||||
aria-haspopup="listbox"
|
||||
disabled={disabled}
|
||||
id={selectId}
|
||||
onClick={() => setOpen((current) => !current)}
|
||||
onClick={() => setOpen((current) => {
|
||||
if (current) setSearchKeyword('');
|
||||
return !current;
|
||||
})}
|
||||
type="button"
|
||||
>
|
||||
<span className={selectedOption?.value ? '' : 'ui-select__placeholder'}>
|
||||
@@ -100,7 +116,13 @@ export function Select({
|
||||
</button>
|
||||
{open ? (
|
||||
<div className="ui-select__dropdown" role="listbox">
|
||||
{options.map((option) => (
|
||||
{searchEnabled ? (
|
||||
<label className="ui-select__search">
|
||||
<Search size={15} />
|
||||
<input autoFocus onChange={(event) => setSearchKeyword(event.target.value)} onKeyDown={(event) => event.stopPropagation()} placeholder={searchPlaceholder ?? '输入名称搜索'} value={searchKeyword} />
|
||||
</label>
|
||||
) : null}
|
||||
{visibleOptions.map((option) => (
|
||||
<button
|
||||
aria-selected={option.value === selectedValue}
|
||||
key={option.value}
|
||||
@@ -111,6 +133,7 @@ export function Select({
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
{visibleOptions.length === 0 ? <span className="ui-select__empty">无匹配选项</span> : null}
|
||||
</div>
|
||||
) : null}
|
||||
</span>
|
||||
|
||||
Reference in New Issue
Block a user