zebflow 0.10.4

Reactive web automation platform — pipelines, templates, and real-time collaboration in a single binary.
Documentation
import { cx, useState } from "zeb/react";

/**
 * Switch — an on/off control with a sliding thumb. Controlled when `checked`
 * is given; otherwise keeps its own state. The track is `bg-input` off and
 * `bg-primary` on, so it follows the theme like every other primitive.
 */
export default function Toggle({ label, checked, onChange, disabled, className, ...rest }) {
  const [own, setOwn] = useState(Boolean(rest?.defaultChecked));
  const isControlled = typeof checked === "boolean";
  const on = isControlled ? checked : own;

  function handleChange(event) {
    if (!isControlled) setOwn(Boolean(event?.target?.checked));
    onChange?.(event);
  }

  return (
    <label
      className={cx(
        "inline-flex items-center gap-2 select-none",
        disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
        className,
      )}
    >
      <input
        type="checkbox"
        role="switch"
        aria-checked={on ? "true" : "false"}
        checked={on}
        onChange={handleChange}
        disabled={disabled}
        className="sr-only"
        {...rest}
      />
      <span
        aria-hidden="true"
        tw-variants="bg-primary bg-input translate-x-4 translate-x-0"
        className={cx(
          "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-transparent transition-colors",
          on ? "bg-primary" : "bg-input",
        )}
      >
        <span
          className={cx(
            "block h-4 w-4 rounded-full bg-background shadow-sm transition-transform",
            on ? "translate-x-4" : "translate-x-0",
          )}
        />
      </span>
      {label ? <span className="text-sm text-foreground">{label}</span> : null}
    </label>
  );
}