All files / src/components collapse.tsx

100% Statements 11/11
100% Branches 3/3
100% Functions 2/2
100% Lines 11/11

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              4x   4x           94x                           94x                 94x                             4x   4x       90x               90x         90x                   4x      
import type { ComponentPropsWithoutRef, ComponentRef } from 'react';
import { forwardRef } from 'react';
import { ChevronDown } from 'lucide-react';
import { Content, Root, Trigger } from '@radix-ui/react-collapsible';
 
import { cn } from '@/lib/utils';
 
const Collapsible = Root;
 
const CollapsibleTrigger = forwardRef<
  ComponentRef<typeof Trigger>,
  ComponentPropsWithoutRef<typeof Trigger> & {
    variant?: 'default' | 'ghost';
  }
>(({ className, variant = 'default', children, ...props }, ref) => {
  const triggerStyles = [
    // Layout
    'flex w-full items-center justify-between',
    // Spacing
    'px-4 py-3',
    // Typography
    'text-sm font-medium',
    // Interactions
    'transition-all',
    'hover:bg-accent hover:text-accent-foreground',
    // Focus states
    // 'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
  ];
 
  const chevronStyles = [
    // Sizing
    'h-4 w-4',
    // Transitions
    'transition-transform duration-200',
    // States
    'data-[state=open]:rotate-180',
  ];
 
  return (
    <Trigger
      ref={ref}
      className={cn(
        triggerStyles.join(' '),
        variant === 'ghost' && 'hover:bg-transparent hover:underline',
        className
      )}
      {...props}
    >
      {children}
      <ChevronDown className={chevronStyles.join(' ')} aria-hidden="true" />
    </Trigger>
  );
});
CollapsibleTrigger.displayName = Trigger.displayName;
 
const CollapsibleContent = forwardRef<
  ComponentRef<typeof Content>,
  ComponentPropsWithoutRef<typeof Content>
>(({ className, children, ...props }, ref) => {
  const contentStyles = [
    // Typography
    'text-sm',
    'overflow-hidden',
    // Animations
    'data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',
  ];
 
  const innerContentStyles = [
    // Spacing
    'px-4 pb-3 pt-0',
  ];
 
  return (
    <Content
      ref={ref}
      className={cn(contentStyles.join(' '), className)}
      {...props}
    >
      <div className={innerContentStyles.join(' ')}>{children}</div>
    </Content>
  );
});
CollapsibleContent.displayName = Content.displayName;
 
export { Collapsible, CollapsibleTrigger, CollapsibleContent };