All files / react-app/src/components/Inputs checkbox.tsx

100% Statements 12/12
100% Branches 11/11
100% Functions 4/4
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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103              105x                                                                                                     105x 105x                 105x 29x                               4x   4x 1x 1x     3x 3x                  
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { Check } from "lucide-react";
import * as React from "react";
import { DependencyWrapperProps } from "shared-types";
 
import { cn } from "@/utils";
 
const CheckboxComponent = React.forwardRef<
  React.ElementRef<typeof CheckboxPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> &
    DependencyWrapperProps & {
      id: string;
      className?: string;
      label?: string;
      value?: string;
      styledLabel?: React.ReactNode;
      description?: string;
      optionlabelClassName?: string;
    }
>(({ className, ...props }, ref) => {
  return (
    <div className="items-top flex space-x-2">
      <CheckboxPrimitive.Root
        ref={ref}
        id={props.id}
        aria-describedby={props.description ? `${props.id}-description` : undefined}
        className={cn(
          "peer h-7 w-7 my-2 shrink-0 rounded-sm border-black border-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:border-primary data-[state=checked]:text-primary-foreground",
          className,
        )}
        {...props}
      >
        <CheckboxPrimitive.Indicator className={cn("flex items-center justify-center text-white")}>
          <Check className="h-4 w-4 stroke-[6px]" />
        </CheckboxPrimitive.Indicator>
      </CheckboxPrimitive.Root>
      <div className="grid gap-1.5 leading-none">
        {!!(props.label || props.styledLabel) && (
          <label
            htmlFor={props.id}
            className={cn(
              "mt-2.5 text-md font-normal leading-normal peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
              props.optionlabelClassName,
            )}
          >
            {props.label || props.styledLabel}
          </label>
        )}
        {!!props.description && (
          <p id={`${props.id}-description`} className="text-sm text-muted-foreground">
            {props.description}
          </p>
        )}
      </div>
    </div>
  );
});
 
CheckboxComponent.displayName = CheckboxPrimitive.Root.displayName;
export const Checkbox = CheckboxComponent;
 
type CheckboxGroupProps = {
  value: string[];
  onChange: (value: string[]) => void;
  options: { label: string; value: string; id: string }[];
  legend?: string;
};
 
export const CheckboxGroup = (props: CheckboxGroupProps) => {
  const [srMessage, setSrMessage] = React.useState("");
 
  return (
    <>
      <div aria-live="assertive" role="status" className="sr-only">
        {srMessage}
      </div>
      <fieldset className="flex flex-col gap-2">
        {props.legend && <legend className="text-md font-semibold mb-2">{props.legend}</legend>}
        {props.options.map((OPT) => (
          <Checkbox
            key={OPT.id}
            id={OPT.id}
            label={OPT.label}
            checked={props.value.includes(OPT.value)}
            onCheckedChange={(c) => {
              const filtered = props.value.filter((f) => f !== OPT.value);
 
              if (!c) {
                setSrMessage(`${OPT.label}. unchecked, checkbox`);
                return props.onChange(filtered);
              }
 
              setSrMessage(`${OPT.label}, checked, checkbox`);
              props.onChange([...filtered, OPT.value]);
            }}
            aria-live="off"
          />
        ))}
      </fieldset>
    </>
  );
};