All files / Radio Radio.tsx

100% Statements 54/54
100% Branches 25/25
100% Functions 11/11
100% Lines 46/46

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 1282x   2x 2x 2x 2x   2x     64x 64x 64x 64x 64x 64x 64x 64x 64x 64x 64x     64x 64x 64x 64x       64x 64x 64x   64x 29x     64x 64x     64x 2x 2x     64x                                                   2x     2x                             64x 64x     64x     64x 64x       64x                       64x     2x 256x   56x   168x   32x    
import React, { forwardRef, useEffect, useState } from "react";
import { RadioProps, RadioStyleProps } from "./Radio.types";
import { useTheme } from "../ThemeProvider/ThemeProvider";
import styled from "styled-components";
import { getColorPalette } from "../../helpers/helpers";
import colorTokens from "../../tokens/colors.json";
 
const Radio = forwardRef(
  (
    {
      index = 0,
      value = "",
      selected = false,
      disabled = false,
      name,
      id,
      className,
      style,
      size = "medium",
      color = colorTokens.default.primary.main,
      focused,
 
      //Events
      onChange,
      getSelectedIndex,
      "data-testid": dataTestId,
      ...props
    }: RadioProps,
    ref
  ) => {
    const innerRef = React.useRef<HTMLInputElement>(null);
    const _ref = (ref ?? innerRef) as React.RefObject<HTMLInputElement>;
    const [isSelected, setIsSelected] = useState(selected);
 
    useEffect(() => {
      setIsSelected(selected);
    }, [selected, focused]);
 
    const theme = useTheme().theme;
    const colorPalette = getColorPalette(theme,color);
 
    // Events
    const _onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
      getSelectedIndex && getSelectedIndex(index);
      onChange && onChange(event);
    };
 
    return (
      <StyledRadio
        role="radio"
        $selected={isSelected}
        $disabled={disabled}
        $size={size}
        $color={color}
        $colorPalette={colorPalette}
        aria-checked={isSelected}
        className={`${className}`}
        style={style}
        data-testid={dataTestId}
        {...props}
      >
        <input
          ref={_ref}
          type="radio"
          checked={isSelected}
          name={name}
          onChange={_onChange}
        />
        <span></span>
      </StyledRadio>
    );
  }
);
export default React.memo(Radio);
 
 
const StyledRadio = styled.span<RadioStyleProps>`
  display: flex;
  align-items: center;
  justify-content: center;
  width: fit-content;
  cursor: pointer;
  padding: 0.5rem;
  border-radius: 50%;
  & input[type="radio"] {
    position: absolute;
    opacity: 0;
    cursor: pointer;
  }
  & input[type="radio"] + span {
    position: relative;
    width: ${(props) => getSize(props.$size)}rem;
    height: ${(props) => getSize(props.$size)}rem;
    border-radius: 50%;
    border: ${(props) =>
      `1.5px solid ${props.$colorPalette[props.$color].accentScale[8]}`};
  }
  & input[type="radio"]:checked + span {
    width: ${(props) => getSize(props.$size)}rem;
    height: ${(props) => getSize(props.$size)}rem;
    border-radius: 50%;
    position: relative;
    border: ${(props) =>
      `1.5px solid ${props.$colorPalette[props.$color].accentScale[8]}`};
  }
  & input[type="radio"]:checked + span:after {
    content: "";
    position: absolute;
    width: 75%;
    height: 75%;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background-color: ${(props) =>
      props.$colorPalette[props.$color].accentScale[8]};
  }
`;
const getSize = (size: RadioStyleProps["$size"]) => {
  switch (size) {
    case "small":
      return 0.875;
    case "medium":
      return 1;
    case "large":
      return 1.5;
  }
};