All files / memory-monitor/src/components/Panel Panel.tsx

100% Statements 5/5
73.68% Branches 14/19
100% Functions 1/1
100% Lines 5/5

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96                                                              1x                             30x 30x   30x                                                                                         1x  
import React, { forwardRef } from "react";
import { clsx } from "clsx";
import type { PanelPosition } from "../../types";
import { Z_INDEX } from "../../constants";
import styles from "./Panel.module.scss";
 
export interface PanelProps {
  /** Whether the panel is open */
  isOpen: boolean;
  /** Position of the panel */
  position?: PanelPosition;
  /** Panel width in pixels */
  width?: number;
  /** Z-index for the panel */
  zIndex?: number;
  /** Whether to show backdrop overlay */
  showBackdrop?: boolean;
  /** Callback when backdrop is clicked */
  onBackdropClick?: () => void;
  /** Custom class name */
  className?: string;
  /** Dark mode */
  isDark?: boolean;
  /** Panel content */
  children: React.ReactNode;
}
 
/**
 * Slide-in panel container component
 * Uses position: fixed for viewport-relative positioning
 */
export const Panel = forwardRef<HTMLDivElement, PanelProps>(
  (
    {
      isOpen,
      position = "right",
      width = 400,
      zIndex = Z_INDEX.panel,
      showBackdrop = false,
      onBackdropClick,
      className,
      isDark = false,
      children,
    },
    ref
  ) => {
    const positionClass = position === "right" ? styles.positionRight : styles.positionLeft;
    const closedClass = position === "right" ? styles.closedRight : styles.closedLeft;
 
    return (
      <>
        {/* Backdrop */}
        {showBackdrop && (
          <div
            className={clsx(
              styles.backdrop,
              isOpen ? styles.open : styles.closed
            )}
            style={{ zIndex: zIndex - 1 }}
            onClick={onBackdropClick}
            aria-hidden="true"
          />
        )}
 
        {/* Panel */}
        <div
          ref={ref}
          role="dialog"
          aria-label="Memory Monitor Panel"
          aria-modal={showBackdrop}
          aria-hidden={!isOpen}
          data-position={position}
          className={clsx(
            styles.panel,
            positionClass,
            isOpen ? styles.open : closedClass,
            isDark && "dark",
            className
          )}
          style={{
            width: `${width}px`,
            zIndex,
          }}
        >
          {/* Inner wrapper with theme-aware styles */}
          <div className={clsx(styles.panelInner, isDark && styles.panelInnerDark)}>
            {children}
          </div>
        </div>
      </>
    );
  }
);
 
Panel.displayName = "Panel";