Skip to content

Animated Toggle View Component (components/Editor/animated-toggle-view.tsx)

Overview

A React component that provides an animated toggle switch for transitioning between split and full view modes. The component features smooth animations, icon indicators, and state synchronization with external controls.

Features

  • Animated toggle transitions
  • Split/Full view modes
  • Icon indicators
  • State synchronization
  • External click handling
  • Disabled state support
  • Spring animations
  • Text transitions
  • Accessibility labels
  • Responsive design
  • Event propagation
  • State persistence
  • Visual feedback
  • Error prevention
  • Cleanup handling

Implementation

export default function AnimatedToggleViewComponent({ 
  onToggle, 
  checked, 
  editedState, 
  clicked 
}: { 
  onToggle: (checked: boolean) => void;
  checked?: boolean;
  editedState: boolean;
  clicked: (newState: boolean) => void;
}) {
  const [isChecked, setIsChecked] = useState(checked || false);

  useEffect(() => {
    setIsChecked(checked || false);
  }, [checked]);

  useEffect(() => {
    const handleExternalClick = (event: MouseEvent) => {
      const target = event.target as HTMLElement;
      if (target.closest('.toggle-label') && editedState) {
        clicked(true);
      }
    };

    document.addEventListener('click', handleExternalClick);
    return () => document.removeEventListener('click', handleExternalClick);
  }, [editedState]);

  const handleToggle = () => {
    if (editedState) return;
    const newChecked = !isChecked;
    setIsChecked(newChecked);
    if (onToggle) onToggle(newChecked);
  }

  return (
    <div className="inline-flex items-center mr-10">
      <label className="relative inline-block w-24 h-12 rounded-full cursor-pointer bg-gray-200 flex-shrink-0 toggle-label">
        <input
          type="checkbox"
          className="sr-only"
          checked={isChecked}
          onChange={handleToggle}
          disabled={editedState}
        />
        <Files className="absolute left-2 top-3 w-6 h-6 text-gray-600" />
        <File className="absolute right-2 top-3 w-6 h-6 text-gray-600" />
        <motion.div
          className="absolute top-1 w-10 h-10 rounded-full shadow-md flex items-center justify-center"
          animate={{
            x: isChecked ? 52 : 2,
            backgroundColor: isChecked ? "#072F75" : "#EE2A7B"
          }}
          transition={{ type: "spring", stiffness: 300, damping: 30 }}
        />
        <span className="sr-only">{isChecked ? 'Full view' : 'Split view'}</span>
      </label>
      <div className="ml-4 flex items-center">
        <div className="flex items-center text-lg font-semibold">
          <AnimatePresence mode="wait">
            <motion.span
              key={isChecked ? 'full' : 'split'}
              initial={{ opacity: 0, y: -20 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: 20 }}
              transition={{ duration: 0.2 }}
              className="mr-1"
            >
              {isChecked ? 'Full' : 'Split'}
            </motion.span>
          </AnimatePresence>
          <span>view</span>
        </div>
      </div>
    </div>
  );
}

Dependencies

import { useState, useEffect } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Files, File } from 'lucide-react'

Components Used

Notes

  • Uses Framer Motion for animations
  • Handles external state synchronization
  • Prevents toggle during edited state
  • Manages click event listeners
  • Provides visual feedback
  • Supports keyboard accessibility
  • Implements smooth transitions
  • Maintains internal state
  • Cleans up event listeners
  • Uses spring animations

Pages/Components Referenced By