mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
feat(navigator): convert search input to a React 19 form action
Replace the onKeyDown Enter handler + onClick button with a
<form action={submitSearch}>. Enter submits natively; the search
button (a styled div, not a real <button>) triggers form submission
via formRef.requestSubmit(), so both paths run the single
FormData-driven handler. The 300ms debounced filter push is kept.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { NavigatorSearchResultSet } from '@nitrots/nitro-renderer';
|
import { NavigatorSearchResultSet } from '@nitrots/nitro-renderer';
|
||||||
import { FC, KeyboardEvent, useEffect, useState } from 'react';
|
import { FC, useEffect, useRef, useState } from 'react';
|
||||||
import { FaSearch } from 'react-icons/fa';
|
import { FaSearch } from 'react-icons/fa';
|
||||||
import { INavigatorSearchFilter, LocalizeText, SearchFilterOptions } from '../../../../api';
|
import { INavigatorSearchFilter, LocalizeText, SearchFilterOptions } from '../../../../api';
|
||||||
import { Button } from '../../../../common';
|
import { Button } from '../../../../common';
|
||||||
@@ -16,6 +16,7 @@ export const NavigatorSearchView: FC<NavigatorSearchViewProps> = props =>
|
|||||||
const { searchResult } = props;
|
const { searchResult } = props;
|
||||||
const [ searchFilterIndex, setSearchFilterIndex ] = useState(0);
|
const [ searchFilterIndex, setSearchFilterIndex ] = useState(0);
|
||||||
const [ inputText, setInputText ] = useState('');
|
const [ inputText, setInputText ] = useState('');
|
||||||
|
const formRef = useRef<HTMLFormElement>(null);
|
||||||
const { topLevelContext } = useNavigatorData();
|
const { topLevelContext } = useNavigatorData();
|
||||||
|
|
||||||
// Sync the input text display when a server result arrives (e.g. on tab switch
|
// Sync the input text display when a server result arrives (e.g. on tab switch
|
||||||
@@ -61,31 +62,27 @@ export const NavigatorSearchView: FC<NavigatorSearchViewProps> = props =>
|
|||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, [ inputText, searchFilterIndex ]);
|
}, [ inputText, searchFilterIndex ]);
|
||||||
|
|
||||||
const processSearch = () =>
|
// React 19 form action — fires on Enter or the submit button, skipping the
|
||||||
|
// debounce timer for an immediate search.
|
||||||
|
const submitSearch = (formData: FormData) =>
|
||||||
{
|
{
|
||||||
if(!topLevelContext) return;
|
if(!topLevelContext) return;
|
||||||
// Immediate submit — skip the debounce timer
|
const raw = formData.get('q');
|
||||||
|
const value = (typeof raw === 'string') ? raw : inputText;
|
||||||
const searchFilter = SearchFilterOptions[searchFilterIndex] ?? SearchFilterOptions[0];
|
const searchFilter = SearchFilterOptions[searchFilterIndex] ?? SearchFilterOptions[0];
|
||||||
const searchQuery = (searchFilter.query ? (searchFilter.query + ':') : '') + inputText;
|
const searchQuery = (searchFilter.query ? (searchFilter.query + ':') : '') + value;
|
||||||
useNavigatorUiStore.getState().setFilter(searchQuery);
|
useNavigatorUiStore.getState().setFilter(searchQuery);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) =>
|
|
||||||
{
|
|
||||||
if(event.key !== 'Enter') return;
|
|
||||||
|
|
||||||
processSearch();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full flex-col gap-1">
|
<div className="flex w-full flex-col gap-1">
|
||||||
<NavigatorFilterChipsView value={ searchFilterIndex } onChange={ setSearchFilterIndex } />
|
<NavigatorFilterChipsView value={ searchFilterIndex } onChange={ setSearchFilterIndex } />
|
||||||
<div className="flex w-full gap-1">
|
<form ref={ formRef } action={ submitSearch } className="flex w-full gap-1">
|
||||||
<input className="w-full form-control" placeholder={ LocalizeText('navigator.filter.input.placeholder') } type="text" value={ inputText } onChange={ event => setInputText(event.target.value) } onKeyDown={ event => handleKeyDown(event) } />
|
<input className="w-full form-control" name="q" placeholder={ LocalizeText('navigator.filter.input.placeholder') } type="text" value={ inputText } onChange={ event => setInputText(event.target.value) } />
|
||||||
<Button variant="primary" onClick={ processSearch }>
|
<Button variant="primary" onClick={ () => formRef.current?.requestSubmit() }>
|
||||||
<FaSearch className="fa-icon" />
|
<FaSearch className="fa-icon" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user