mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-18 09:20:15 +01:00
102 lines
2.7 KiB
TypeScript
102 lines
2.7 KiB
TypeScript
|
|
import React, { useEffect, useState, useRef } from 'react';
|
||
|
|
import { EditIcon, SaveIcon } from '~/components/svg';
|
||
|
|
|
||
|
|
type Props = {
|
||
|
|
name?: string;
|
||
|
|
onSave: (newName: string) => void;
|
||
|
|
};
|
||
|
|
|
||
|
|
const PromptName: React.FC<Props> = ({ name, onSave }) => {
|
||
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
||
|
|
const blurTimeoutRef = useRef<NodeJS.Timeout>();
|
||
|
|
const [isEditing, setIsEditing] = useState(false);
|
||
|
|
const [newName, setNewName] = useState(name);
|
||
|
|
|
||
|
|
const handleEditClick = () => {
|
||
|
|
setIsEditing(true);
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||
|
|
setNewName(e.target.value);
|
||
|
|
};
|
||
|
|
|
||
|
|
const saveName = () => {
|
||
|
|
const savedName = newName?.trim();
|
||
|
|
onSave(savedName || '');
|
||
|
|
setIsEditing(false);
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleSaveClick: React.MouseEventHandler<HTMLButtonElement> = () => {
|
||
|
|
saveName();
|
||
|
|
clearTimeout(blurTimeoutRef.current);
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleBlur = () => {
|
||
|
|
blurTimeoutRef.current = setTimeout(() => {
|
||
|
|
if (document.activeElement !== inputRef.current) {
|
||
|
|
setIsEditing(false);
|
||
|
|
setNewName(name);
|
||
|
|
}
|
||
|
|
}, 200);
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||
|
|
if (e.key === 'Escape') {
|
||
|
|
setIsEditing(false);
|
||
|
|
setNewName(name);
|
||
|
|
}
|
||
|
|
if (e.key === 'Enter' || e.key === 'Tab') {
|
||
|
|
saveName();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (isEditing) {
|
||
|
|
inputRef.current?.focus();
|
||
|
|
}
|
||
|
|
}, [isEditing]);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
setNewName(name);
|
||
|
|
}, [name]);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="mb-1 flex flex-row items-center font-bold sm:text-xl md:mb-0 md:text-2xl">
|
||
|
|
{isEditing ? (
|
||
|
|
<div className="mb-1 flex items-center md:mb-0">
|
||
|
|
<input
|
||
|
|
type="text"
|
||
|
|
value={newName ?? ''}
|
||
|
|
onChange={handleInputChange}
|
||
|
|
onBlur={handleBlur}
|
||
|
|
onKeyDown={handleKeyDown}
|
||
|
|
ref={inputRef}
|
||
|
|
className="mr-2 w-56 rounded-md border bg-transparent p-2 focus:outline-none dark:border-gray-600 md:w-auto"
|
||
|
|
autoFocus={true}
|
||
|
|
/>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={handleSaveClick}
|
||
|
|
className="rounded p-2 hover:bg-gray-300/50 dark:hover:bg-gray-700"
|
||
|
|
>
|
||
|
|
<SaveIcon className="icon-md" size="1.2em" />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
) : (
|
||
|
|
<div className="mb-1 flex items-center md:mb-0">
|
||
|
|
<span className="border border-transparent p-2">{newName}</span>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={handleEditClick}
|
||
|
|
className="rounded p-2 hover:bg-gray-300/50 dark:hover:bg-gray-700"
|
||
|
|
>
|
||
|
|
<EditIcon className="icon-md" />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default PromptName;
|