import { useEffect, type Ref } from 'react' import { Input } from './Input' import styles from './SearchField.module.css' /** * 搜索框:带搜索图标、可清空、可挂快捷键提示。 * * 与 `Input` 的区别是「语义」而不是外观:对外只给字符串(`value` / `onChange(string)`), * 使用方不用再写 `event.target.value`;外观用 `variant` 切,不用改组件。 */ export type SearchFieldProps = { value: string onChange: (value: string) => void placeholder?: string /** 右侧快捷键提示,如 `⌘K`(仅展示) */ shortcut?: string /** 高度:36 / 44 */ size?: 'md' | 'lg' /** plain = 与普通输入框一致;card = 实底 + 柔和阴影(悬浮搜索条的样子) */ variant?: 'plain' | 'card' /** 最大宽度,默认 480 */ maxWidth?: number | string /** 按下 Ctrl/Cmd + 该键时聚焦并全选(需要同时传 inputRef) */ hotkey?: string /** Esc 清空,默认开 */ clearOnEscape?: boolean inputRef?: Ref /** 无障碍名称,默认取 placeholder */ label?: string className?: string id?: string } export function SearchField({ value, onChange, placeholder = '搜索…', shortcut, size = 'lg', variant = 'plain', maxWidth = 480, hotkey, clearOnEscape = true, inputRef, label, className, id, }: SearchFieldProps) { const classes = [styles.root, className].filter(Boolean).join(' ') useEffect(() => { if (hotkey === undefined || hotkey === '' || inputRef === undefined || inputRef === null) return if (!('current' in inputRef)) return const target = inputRef const key = hotkey.toLowerCase() const handleKeyDown = (event: KeyboardEvent) => { if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== key) return const element = target.current if (element === null) return event.preventDefault() element.focus() element.select() } window.addEventListener('keydown', handleKeyDown) return () => window.removeEventListener('keydown', handleKeyDown) }, [hotkey, inputRef]) return (
onChange('')} spellCheck={false} className={variant === 'card' ? styles.card : undefined} onChange={(event) => onChange(event.target.value)} onKeyDown={(event) => { if (clearOnEscape && event.key === 'Escape') onChange('') }} />
) }