chenzhaoyang
2025-12-17 063da0bf961e1d35e25dc107f883f7492f4c5a7c
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
import { forwardRef, useCallback, useEffect, useMemo, useState } from "react";
import clsx from "clsx";
import { Label } from "@humansignal/ui";
import styles from "./toggle.module.scss";
 
type ToggleProps = {
  className?: string;
  label?: string;
  labelProps?: Partial<React.ComponentProps<typeof Label>>;
  description?: string;
  checked?: boolean;
  defaultChecked?: boolean;
  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
  required?: boolean;
  style?: React.CSSProperties;
  disabled?: boolean;
  alwaysBlue?: boolean;
};
 
export const Toggle = forwardRef<HTMLInputElement, ToggleProps>(
  (
    {
      className,
      label,
      labelProps,
      description,
      checked,
      defaultChecked,
      onChange,
      required,
      style,
      alwaysBlue,
      ...props
    },
    ref,
  ) => {
    const initialChecked = useMemo(() => defaultChecked ?? checked ?? false, [defaultChecked, checked]);
    const [isChecked, setIsChecked] = useState<boolean>(defaultChecked ?? checked ?? false);
    useEffect(() => {
      setIsChecked(initialChecked);
    }, [initialChecked]);
 
    const onChangeHandler = useCallback(
      (e: React.ChangeEvent<HTMLInputElement>) => {
        if (typeof checked === "undefined") {
          setIsChecked(e.target.checked);
        }
        onChange?.(e);
      },
      [onChange, checked],
    );
 
    const formField = (
      <div
        className={clsx(
          styles.toggle,
          {
            [styles.toggle_disabled]: props.disabled,
            [styles.toggle_checked]: isChecked,
            [styles.toggle_alwaysBlue]: alwaysBlue,
          },
          className,
        )}
        style={style}
      >
        <input
          {...props}
          ref={ref}
          className={clsx(styles.toggle__input)}
          type="checkbox"
          checked={isChecked}
          onChange={onChangeHandler}
        />
        <span className={clsx(styles.toggle__indicator)} />
      </div>
    );
 
    return label ? (
      <Label
        placement="right"
        required={required}
        text={label}
        description={description}
        className="gap-2"
        {...(labelProps ?? {})}
      >
        {formField}
      </Label>
    ) : (
      formField
    );
  },
);