loading
Just a moment.

Input Morph Message

November 2024

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;