mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-23 08:56:42 +08:00
Fix: search input cannot expand to show long queries (#17166)
This commit is contained in:
20
web/src/hooks/use-auto-resize-textarea.ts
Normal file
20
web/src/hooks/use-auto-resize-textarea.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { useLayoutEffect, type RefObject } from 'react';
|
||||
|
||||
/**
|
||||
* Auto-resize a textarea to fit its content, clamped to a maximum height.
|
||||
*
|
||||
* useLayoutEffect runs synchronously after DOM mutation but before the
|
||||
* browser paints, so the height adjustment never produces a visible flicker.
|
||||
*/
|
||||
export function useAutoResizeTextarea(
|
||||
ref: RefObject<HTMLTextAreaElement | null>,
|
||||
value: string,
|
||||
maxHeight = 160,
|
||||
) {
|
||||
useLayoutEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
el.style.height = 'auto';
|
||||
el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;
|
||||
}, [ref, value, maxHeight]);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Input } from '@/components/originui/input';
|
||||
import Spotlight from '@/components/spotlight';
|
||||
import message from '@/components/ui/message';
|
||||
import { IUserInfo } from '@/interfaces/database/user-setting';
|
||||
import { useAutoResizeTextarea } from '@/hooks/use-auto-resize-textarea';
|
||||
import { Search } from 'lucide-react';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { Dispatch, SetStateAction, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import './index.less';
|
||||
import { RAGFlowLogo } from './ragflow-logo';
|
||||
@@ -27,6 +27,10 @@ export default function SearchHome({
|
||||
}) {
|
||||
// const { data: userInfo } = useFetchUserInfo();
|
||||
const { t } = useTranslation();
|
||||
const searchInputRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
useAutoResizeTextarea(searchInputRef, searchText);
|
||||
|
||||
return (
|
||||
<section className="relative w-full flex transition-all justify-center items-center mt-[15vh]">
|
||||
<div className="relative z-10 px-8 pt-8 flex text-transparent flex-col justify-center items-center w-[780px]">
|
||||
@@ -48,12 +52,19 @@ export default function SearchHome({
|
||||
)}
|
||||
|
||||
<div className="relative w-full ">
|
||||
<Input
|
||||
<textarea
|
||||
ref={searchInputRef}
|
||||
rows={1}
|
||||
placeholder={t('search.searchGreeting')}
|
||||
className="w-full rounded-full py-7 px-4 pr-10 text-text-primary text-lg bg-bg-base delay-700"
|
||||
className="w-full rounded-3xl py-4 px-4 pr-14 text-text-primary text-lg bg-bg-base delay-700 border border-border-button resize-none overflow-y-auto scrollbar-thin outline-none focus-visible:ring-1 focus-visible:ring-text-primary/50"
|
||||
value={searchText}
|
||||
onKeyUp={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
onKeyDown={(e) => {
|
||||
if (
|
||||
e.key === 'Enter' &&
|
||||
!e.shiftKey &&
|
||||
!e.nativeEvent.isComposing
|
||||
) {
|
||||
e.preventDefault();
|
||||
if (canSearch === false) {
|
||||
message.warning(t('search.chooseDataset'));
|
||||
return;
|
||||
|
||||
@@ -3,7 +3,6 @@ import Empty from '@/components/empty/empty';
|
||||
import HighLightMarkdown from '@/components/highlight-markdown';
|
||||
import { FileIcon } from '@/components/icon-font';
|
||||
import { ImageWithPopover } from '@/components/image';
|
||||
import { Input } from '@/components/originui/input';
|
||||
import { SkeletonCard } from '@/components/skeleton-card';
|
||||
import { TopSelect } from '@/components/top-select';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -13,10 +12,11 @@ import {
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover';
|
||||
import { IReference } from '@/interfaces/database/chat';
|
||||
import { useAutoResizeTextarea } from '@/hooks/use-auto-resize-textarea';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { ListTree, Search, X } from 'lucide-react';
|
||||
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||
import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ISearchAppDetailProps } from '../next-searches/hooks';
|
||||
import PdfDrawer from './document-preview-modal';
|
||||
@@ -73,11 +73,14 @@ export default function SearchingView({
|
||||
|
||||
const [searchText, setSearchText] = useState<string>('');
|
||||
const [retrievalLoading, setRetrievalLoading] = useState(false);
|
||||
const searchInputRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setSearchText(searchStr);
|
||||
}, [searchStr, setSearchText]);
|
||||
|
||||
useAutoResizeTextarea(searchInputRef, searchText);
|
||||
|
||||
return (
|
||||
<section
|
||||
className={cn(
|
||||
@@ -103,18 +106,25 @@ export default function SearchingView({
|
||||
>
|
||||
<div className={cn('flex flex-col justify-start items-start w-full')}>
|
||||
<div className="relative w-full text-primary">
|
||||
<Input
|
||||
<textarea
|
||||
ref={searchInputRef}
|
||||
rows={1}
|
||||
placeholder={t('search.searchGreeting')}
|
||||
className={cn(
|
||||
'w-full rounded-full py-6 pl-4 !pr-[8rem] text-primary text-lg bg-bg-base',
|
||||
'w-full rounded-3xl py-4 pl-4 !pr-[8rem] text-primary text-lg bg-bg-base border border-border-button resize-none overflow-y-auto scrollbar-thin outline-none focus-visible:ring-1 focus-visible:ring-text-primary/50 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
)}
|
||||
value={searchText}
|
||||
onChange={(e) => {
|
||||
setSearchText(e.target.value);
|
||||
}}
|
||||
disabled={sendingLoading}
|
||||
onKeyUp={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
onKeyDown={(e) => {
|
||||
if (
|
||||
e.key === 'Enter' &&
|
||||
!e.shiftKey &&
|
||||
!e.nativeEvent.isComposing
|
||||
) {
|
||||
e.preventDefault();
|
||||
handleSearch(searchText);
|
||||
}
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user