mirror of
https://github.com/pheralb/svgl.git
synced 2025-02-06 06:58:04 +08:00
feat: add autofocus when open search box
This commit is contained in:
parent
b42afebd9d
commit
422af78d44
@ -1,18 +1,27 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Input, Text, Image, HStack, Box, Center, Spinner } from "@chakra-ui/react";
|
import {
|
||||||
|
Input,
|
||||||
|
Text,
|
||||||
|
Image,
|
||||||
|
HStack,
|
||||||
|
Box,
|
||||||
|
Center,
|
||||||
|
Spinner,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
import useDebounce from "@/hooks/useDebounce";
|
import useDebounce from "@/hooks/useDebounce";
|
||||||
import { SVGCardProps } from "@/interfaces/components";
|
import { SearchProps, SVGCardProps } from "@/interfaces/components";
|
||||||
import CustomLink from "@/common/link";
|
import CustomLink from "@/common/link";
|
||||||
import { getSvgByQuery } from "@/services";
|
import { getSvgByQuery } from "@/services";
|
||||||
import CustomIconBtn from "@/common/iconBtn";
|
import CustomIconBtn from "@/common/iconBtn";
|
||||||
import { Trash } from "phosphor-react";
|
import { Trash } from "phosphor-react";
|
||||||
import Tap from "@/animations/tap";
|
import Tap from "@/animations/tap";
|
||||||
|
|
||||||
const Search = () => {
|
const Search = ({ availableFocus = false }: SearchProps) => {
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [empty, setEmpty] = useState(false);
|
const [empty, setEmpty] = useState(false);
|
||||||
const [results, setResults] = useState<SVGCardProps[]>([]);
|
const [results, setResults] = useState<SVGCardProps[]>([]);
|
||||||
const debouncedSearch = useDebounce(search, 500);
|
const debouncedSearch = useDebounce(search, 500);
|
||||||
|
const searchRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (debouncedSearch) {
|
if (debouncedSearch) {
|
||||||
@ -27,6 +36,18 @@ const Search = () => {
|
|||||||
}
|
}
|
||||||
}, [debouncedSearch]);
|
}, [debouncedSearch]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const isFocusAvailable = availableFocus && searchRef.current;
|
||||||
|
|
||||||
|
if (!isFocusAvailable) return;
|
||||||
|
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
searchRef.current?.focus();
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
return () => clearTimeout(timeoutId);
|
||||||
|
}, [availableFocus]);
|
||||||
|
|
||||||
const handleFilter = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleFilter = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setEmpty(false);
|
setEmpty(false);
|
||||||
setSearch(e.target.value);
|
setSearch(e.target.value);
|
||||||
@ -46,12 +67,23 @@ const Search = () => {
|
|||||||
placeholder="Search svgs..."
|
placeholder="Search svgs..."
|
||||||
value={search}
|
value={search}
|
||||||
onChange={handleFilter}
|
onChange={handleFilter}
|
||||||
|
ref={searchRef}
|
||||||
/>
|
/>
|
||||||
{search && !empty && results.length === 0 && (<Box pt="4"><Spinner /></Box>)}
|
{search && !empty && results.length === 0 && (
|
||||||
{search && empty && (<Box pt="3">No results found!</Box>)}
|
<Box pt="4">
|
||||||
|
<Spinner />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
{search && empty && <Box pt="3">No results found!</Box>}
|
||||||
{results && results.length > 0 && (
|
{results && results.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<HStack spacing={4} mt={4} overflowX="auto" overflowY="hidden" alignItems="start">
|
<HStack
|
||||||
|
spacing={4}
|
||||||
|
mt={4}
|
||||||
|
overflowX="auto"
|
||||||
|
overflowY="hidden"
|
||||||
|
alignItems="start"
|
||||||
|
>
|
||||||
{results.map((item: SVGCardProps) => (
|
{results.map((item: SVGCardProps) => (
|
||||||
<Tap key={item.title}>
|
<Tap key={item.title}>
|
||||||
<CustomLink href={`/svg/${item.id}`}>
|
<CustomLink href={`/svg/${item.id}`}>
|
||||||
|
@ -42,3 +42,7 @@ export interface ErrorProps {
|
|||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SearchProps {
|
||||||
|
availableFocus?: boolean;
|
||||||
|
}
|
||||||
|
@ -91,7 +91,7 @@ const Header = () => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
<Collapse in={isOpen} animateOpacity>
|
<Collapse in={isOpen} animateOpacity>
|
||||||
<Box mt='3' display={{ base: 'none', md: 'block' }}>
|
<Box mt='3' display={{ base: 'none', md: 'block' }}>
|
||||||
<Search />
|
<Search availableFocus={isOpen} />
|
||||||
</Box>
|
</Box>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
<Box mt='2' display={{ base: 'block', md: 'none' }}>
|
<Box mt='2' display={{ base: 'block', md: 'none' }}>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user