diff --git a/src/renderer/features/shared/components/search-input.tsx b/src/renderer/features/shared/components/search-input.tsx index 8159683e1..1633e99f8 100644 --- a/src/renderer/features/shared/components/search-input.tsx +++ b/src/renderer/features/shared/components/search-input.tsx @@ -1,21 +1,45 @@ import { useHotkeys } from '@mantine/hooks'; -import { ChangeEvent, KeyboardEvent, useRef, useState } from 'react'; +import { ChangeEvent, CSSProperties, KeyboardEvent, useRef, useState } from 'react'; import { shallow } from 'zustand/shallow'; import { useSettingsStore } from '/@/renderer/store'; -import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; +import { ActionIcon, ActionIconProps } from '/@/shared/components/action-icon/action-icon'; +import { Box } from '/@/shared/components/box/box'; import { Icon } from '/@/shared/components/icon/icon'; import { TextInput, TextInputProps } from '/@/shared/components/text-input/text-input'; interface SearchInputProps extends TextInputProps { + buttonProps?: Partial; + enableHotkey?: boolean; + inputProps?: Partial; value?: string; } -export const SearchInput = ({ onChange, ...props }: SearchInputProps) => { +export const SearchInput = ({ + buttonProps, + enableHotkey = true, + inputProps, + onChange, + ...props +}: SearchInputProps) => { const ref = useRef(null); const binding = useSettingsStore((state) => state.hotkeys.bindings.localSearch, shallow); + const [isInputMode, setIsInputMode] = useState(false); - useHotkeys([[binding.hotkey, () => ref?.current?.select()]]); + useHotkeys([ + [ + binding.hotkey, + () => { + if (enableHotkey) { + setIsInputMode(true); + setTimeout(() => { + ref?.current?.focus(); + ref?.current?.select(); + }, 0); + } + }, + ], + ]); const handleEscape = (e: KeyboardEvent) => { if (e.code === 'Escape') { @@ -24,6 +48,7 @@ export const SearchInput = ({ onChange, ...props }: SearchInputProps) => { ref.current.value = ''; ref.current.blur(); } + setIsInputMode(false); } }; @@ -35,27 +60,76 @@ export const SearchInput = ({ onChange, ...props }: SearchInputProps) => { } }; - const [isFocused, setIsFocused] = useState(false); + const handleButtonClick = () => { + setIsInputMode(true); + setTimeout(() => { + ref?.current?.focus(); + }, 0); + }; + + const handleBlur = () => { + const hasValue = props.value || ref.current?.value; + if (!hasValue) { + setIsInputMode(false); + } + }; const hasValue = props.value || ref.current?.value; + const shouldShowInput = isInputMode || hasValue; + + const containerStyle: CSSProperties = { + display: 'inline-flex', + overflow: 'hidden', + position: 'relative', + transition: 'width 0.3s ease-in-out', + width: shouldShowInput ? '200px' : '40px', + }; + + const buttonStyle: CSSProperties = { + left: 0, + opacity: shouldShowInput ? 0 : 1, + pointerEvents: shouldShowInput ? 'none' : 'auto', + position: 'absolute', + top: 0, + transition: 'opacity 0.2s ease-in-out', + zIndex: 10, + }; + + const inputStyle: CSSProperties = { + opacity: shouldShowInput ? 1 : 0, + transition: 'opacity 0.2s ease-in-out', + width: '100%', + }; return ( - } - maw="20dvw" - onBlur={() => setIsFocused(false)} - onChange={onChange} - onFocus={() => setIsFocused(true)} - onKeyDown={handleEscape} - ref={ref} - size="sm" - width={isFocused || hasValue ? '200px' : '100px'} - {...props} - rightSection={ - ref.current?.value ? ( - - ) : null - } - /> + + } + maw="20dvw" + {...inputProps} + onBlur={handleBlur} + onChange={onChange} + onFocus={() => setIsInputMode(true)} + onKeyDown={handleEscape} + ref={ref} + size="sm" + style={inputStyle} + {...props} + rightSection={ + ref.current?.value ? ( + + ) : null + } + /> + + ); };