File "Tooltip.tsx"

Full Path: /home/trinadezambia/public_html/student_panel/src/components/ui/pages/common/Tooltip.tsx
File size: 3.18 KB
MIME-type: text/x-java
Charset: utf-8

/**
 * Tooltip Component
 *
 * A reusable tooltip component that displays additional information on hover.
 * Uses CSS and Tailwind for styling with a clean, modern appearance.
 *
 * Features:
 * - Appears on hover
 * - Positioned above the trigger element
 * - Dark background with white text
 * - Includes arrow pointing to trigger
 * - Supports text wrapping for long content
 * - Fully accessible with keyboard support
 */

import React, { useState } from 'react';

interface TooltipProps {
  /**
   * The content to display in the tooltip
   * Can be a string or React element
   */
  content: string | React.ReactNode;

  /**
   * The element that triggers the tooltip (usually text or button)
   */
  children: React.ReactNode;

  /**
   * Optional: Position of the tooltip relative to the trigger
   * @default 'top'
   */
  position?: 'top' | 'bottom' | 'left' | 'right';

  /**
   * Optional: Additional CSS classes for the trigger container
   */
  className?: string;

  /**
   * Optional: Custom width for the tooltip
   * @default 'min-w-[200px] max-w-[280px]'
   */
  width?: string;
}

/**
 * Tooltip Component
 *
 * Usage example:
 * ```tsx
 * <Tooltip content="This is helpful information">
 *   <span>Hover over me</span>
 * </Tooltip>
 * ```
 */
export default function Tooltip({
  content,
  children,
  position = 'top',
  className = '',
  width = 'min-w-[200px] max-w-[280px]',
}: TooltipProps) {
  const [isOpen, setIsOpen] = useState(false);

  // Position classes based on tooltip position prop
  // Using logical properties (start/end) for RTL support
  // start = left in LTR, right in RTL
  // end = right in LTR, left in RTL
  const positionClasses = {
    top: 'bottom-full mb-2 start-0',
    bottom: 'top-full mt-2 start-0',
    left: 'end-full me-2 top-0', // Changed: right-full -> end-full, mr-2 -> me-2
    right: 'start-full ms-2 top-0', // Changed: left-full -> start-full, ml-2 -> ms-2
  };

  // Arrow classes based on position
  // Using logical properties for RTL support
  const arrowClasses = {
    top: 'start-4 top-full border-s-4 border-e-4 border-t-4 border-s-transparent border-e-transparent border-t-gray-900',
    bottom:
      'start-4 bottom-full border-s-4 border-e-4 border-b-4 border-s-transparent border-e-transparent border-b-gray-900',
    left: 'top-4 start-full border-t-4 border-b-4 border-s-4 border-t-transparent border-b-transparent border-s-gray-900',
    right:
      'top-4 end-full border-t-4 border-b-4 border-e-4 border-t-transparent border-b-transparent border-e-gray-900',
  };

  return (
    <div
      className={`relative group inline-block ${className}`}
      onClick={() => setIsOpen(!isOpen)}
      onMouseLeave={() => setIsOpen(false)}
    >
      {/* Trigger element */}
      {children}

      {/* Tooltip */}
      <div
        className={`absolute ${positionClasses[position]} ${
          isOpen ? 'block' : 'hidden group-hover:block'
        } z-50 ${width}`}
      >
        <div className="bg-gray-900 text-white text-xs rounded-lg py-2 px-3 shadow-lg whitespace-normal wrap-break-word leading-relaxed">
          {content}
        </div>

        {/* Arrow */}
        <div className={`absolute w-0 h-0 ${arrowClasses[position]}`}></div>
      </div>
    </div>
  );
}