Input Morph Message
November 2024
TSX
import { AnimatePresence, motion } from 'framer-motion';
import { useState } from 'react';
const transitionDebug = {
type: 'easeOut',
duration: 0.2,
};
interface IconProps {
className?: string;
color?: string;
}
const PlusIcon = (params: IconProps) => {
return (
<svg
className={params.className}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke={params.color}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 4.5v15m7.5-7.5h-15"
/>
</svg>
);
};
const InputMorphMessage = () => {
const [messages, setMessages] = useState<
{
id: number;
text: string;
}[]
>([]);
const [newMessage, setNewMessage] = useState<string>('');
const handleSubmit = (e: { preventDefault: () => void }) => {
e.preventDefault();
if (newMessage.trim()) {
const timestamp = new Date().getTime();
setMessages([...messages, { id: timestamp, text: newMessage }]);
setNewMessage('');
}
};
return (
<div className="flex h-[300px] flex-col items-end justify-end pb-4">
<AnimatePresence mode="wait">
{messages.map((message) => (
<motion.div
key={message.id}
layout="position"
className="z-10 mt-2 max-w-[250px] break-words rounded-2xl bg-[#101010]"
layoutId={`container-[${messages.length - 1}]`}
transition={transitionDebug}
>
<div className="px-3 py-2 text-[15px] leading-[15px] text-gray-900 dark:text-gray-100">
{message.text}
</div>
</motion.div>
))}
</AnimatePresence>
<div className="mt-4 flex w-full">
<form onSubmit={handleSubmit} className="flex w-full">
<input
type="text"
onChange={(e) => setNewMessage(e.target.value)}
value={newMessage}
className="relative h-9 w-[250px] flex-grow rounded-full border px-3 text-[15px] outline-none focus-visible:ring-0
border-white/[0.05] bg-[#101010] text-gray-50 placeholder-white/30 focus-visible:ring-offset-1 focus-visible:ring-offset-gray-700 hover:border-white/20 transition-all"
placeholder="Type your message"
/>
<motion.div
key={messages.length}
layout="position"
className="pointer-events-none absolute z-10 flex h-9 w-[250px] items-center overflow-hidden break-words rounded-full [word-break:break-word] bg-[#101010]"
layoutId={`container-[${messages.length}]`}
transition={transitionDebug}
initial={{ opacity: 0.6, zIndex: -1 }}
animate={{ opacity: 0.6, zIndex: -1 }}
exit={{ opacity: 1, zIndex: 1 }}
>
<div className="px-3 py-2 text-[15px] leading-[15px] text-gray-900 dark:text-gray-50">
{newMessage}
</div>
</motion.div>
<button
type="submit"
className="ml-2 flex h-9 w-9 items-center justify-center rounded-full border border-white/[0.05] border-solid bg-[#101010] hover:scale-105 hover:border-white/10 hover:bg-white/[0.05] transition-all"
>
<PlusIcon className="h-5 w-5" color="rgb(75 85 99)" />
</button>
</form>
</div>
</div>
);
};
export default InputMorphMessage;