All files / atoms/CheckBox/mobile CheckBox.native.tsx

97.36% Statements 37/38
94.23% Branches 49/52
100% Functions 7/7
97.29% Lines 36/37

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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148                  4x                                 182x   182x   182x 151x     151x       182x 2x   1x   1x       182x 180x   17x   163x       182x         182x 182x   1x   180x   1x       182x 182x   182x               182x           182x     182x           182x         182x 182x 176x                           6x     182x 13x 10x 10x     182x                                      
import React, { useEffect, useState } from 'react';
import { CheckBoxNativeProps } from './CheckBox.native.types';
import { Pressable, StyleProp, Text, View, ViewStyle } from 'react-native';
import { cn } from '@sb/libs';
import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { colors } from '@sb/styles/colors';
import { useTheme } from '@sb/ui/components/Themes/ThemeProvider';
 
export const CheckBox: React.FC<CheckBoxNativeProps> = ({
  id,
  label,
  defaultChecked = false,
  checked,
  onChange,
  disabled = false,
  readOnly = false,
  size = 'medium',
  variant = 'primary',
  direction = 'row',
  status,
  partialChecked = false,
  onFocus,
  onBlur,
  className,
}) => {
  const [isChecked, setIsChecked] = useState(checked !== undefined ? checked : false);
 
  const { theme } = useTheme();
 
  useEffect(() => {
    Iif (defaultChecked) {
      setIsChecked(true);
    } else {
      setIsChecked(checked ?? false);
    }
  }, [checked, defaultChecked]);
 
  const getStatusColor = () => {
    switch (status) {
      case 'error':
        return colors[theme].colorStatus_Error;
      case 'warning':
        return colors[theme].colorStatus_Warning;
    }
  };
 
  const getVariantColor = () => {
    switch (variant) {
      case 'primary':
        return colors[theme].colorTertiary;
      case 'secondary':
        return colors[theme].colorAccent;
    }
  };
 
  const wrapperStyle: StyleProp<ViewStyle> = {
    flexDirection: direction === 'column' ? 'column' : 'row',
    justifyContent: 'flex-start',
  };
 
  const getSize = () => {
    switch (size) {
      case 'small':
        return 16;
      case 'medium':
        return 20;
      case 'large':
        return 32;
    }
  };
 
  const checkSize = getSize();
  const color = isChecked && status && status !== 'default' ? getStatusColor() : getVariantColor();
 
  const iconStyle: StyleProp<ViewStyle> = {
    opacity: disabled ? 0.5 : 1,
    backgroundColor: color,
    height: 20,
    width: 20,
  };
 
  const uncheckedIcon = (
    <View
      className={cn('rounded-[3px]', className)}
      style={{ height: 20, width: 20, borderWidth: 1, borderColor: colors[theme].borderWhite }}
    ></View>
  );
 
  const iconColor = (variant === 'primary' && !status) || status == 'default' ? 'white' : 'black';
 
  const checkIcon = (
    <View style={iconStyle} className={cn('rounded-[3px]', className)}>
      <MaterialCommunityIcons name="check" size={checkSize} color={iconColor} />
    </View>
  );
 
  const intermediateIcon = (
    <View style={iconStyle} className={cn('rounded-[3px]', className)}>
      <MaterialIcons name="horizontal-rule" size={checkSize} color={iconColor} />
    </View>
  );
 
  const renderLabel = () => {
    if (typeof label === 'string') {
      return (
        <Text
          accessibilityLabel={label}
          className={cn(
            'text-text-main whitespace-normal font-normal',
            direction === 'row' && 'ml-[10px]',
            direction === 'column' && 'mt-[10px]'
          )}
        >
          {label}
        </Text>
      );
    }
 
    return label;
  };
 
  const handleChange = () => {
    if (readOnly || disabled) return;
    setIsChecked(!isChecked);
    onChange?.(!isChecked);
  };
 
  return (
    <Pressable
      accessible
      accessibilityRole="checkbox"
      accessibilityState={{ checked }}
      id={id}
      testID={id}
      onPress={handleChange}
      onFocus={onFocus}
      onBlur={onBlur}
      style={wrapperStyle}
    >
      <View style={wrapperStyle}>
        {isChecked && partialChecked ? intermediateIcon : isChecked ? checkIcon : uncheckedIcon}
        {label && renderLabel()}
      </View>
    </Pressable>
  );
};