fix: clarify signature reporting status

This commit is contained in:
hectorzhao
2026-07-13 10:16:12 +08:00
parent 551edfd8ca
commit 344b2afe3b
13 changed files with 140 additions and 26 deletions
+26 -3
View File
@@ -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>