zebflow 0.6.1

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

interface ToggleGroupProps {
  type?: "single" | "multiple";
  value?: string | string[];
  defaultValue?: string | string[];
  onValueChange?: (value: string | string[]) => void;
  variant?: "default" | "outline";
  size?: "default" | "sm" | "lg";
  disabled?: boolean;
  className?: string;
  children?: any;
  [key: string]: any;
}

interface ToggleGroupItemProps {
  value: string;
  disabled?: boolean;
  className?: string;
  children?: any;
  // injected
  _type?: string;
  _activeValues?: string[];
  _onToggle?: (v: string) => void;
  _variant?: string;
  _size?: string;
  [key: string]: any;
}

const ITEM_VARIANTS = {
  default: "bg-transparent hover:bg-gray-100 hover:text-gray-900 data-[state=on]:bg-gray-100 data-[state=on]:text-gray-900",
  outline: "border border-gray-200 bg-transparent hover:bg-gray-100 hover:text-gray-900 data-[state=on]:bg-gray-100 data-[state=on]:text-gray-900",
};

const ITEM_SIZES = {
  default: "h-9 px-3 min-w-9",
  sm:      "h-8 px-2 min-w-8",
  lg:      "h-10 px-5 min-w-10",
};

export function ToggleGroup({ type = "single", value, defaultValue, onValueChange, variant = "default", size = "default", disabled, className, children, ...rest }: ToggleGroupProps) {
  const toArr = (v?: string | string[]) => v ? (Array.isArray(v) ? v : [v]) : [];
  const [internal, setInternal] = useState<string[]>(toArr(defaultValue));
  const controlled = value !== undefined;
  const active = controlled ? toArr(value) : internal;

  const handleToggle = (v: string) => {
    if (disabled) return;
    let next: string[];
    if (type === "single") {
      next = active.includes(v) ? [] : [v];
    } else {
      next = active.includes(v) ? active.filter(x => x !== v) : [...active, v];
    }
    if (!controlled) setInternal(next);
    onValueChange?.(type === "single" ? (next[0] ?? "") : next);
  };

  const items = Array.isArray(children) ? children : [children];
  const enhanced = items.map((child: any) => {
    if (!child || typeof child !== "object") return child;
    return { ...child, props: { ...child.props, _type: type, _activeValues: active, _onToggle: handleToggle, _variant: variant, _size: size } };
  });

  return (
    <div
      role="group"
      className={cx("flex items-center justify-center gap-1", className)}
      {...rest}
    >
      {enhanced}
    </div>
  );
}

export function ToggleGroupItem({ value, disabled, className, children, _activeValues, _onToggle, _variant = "default", _size = "default", ...rest }: ToggleGroupItemProps) {
  const isOn = _activeValues?.includes(value) ?? false;
  return (
    <button
      type="button"
      data-state={isOn ? "on" : "off"}
      disabled={disabled}
      onClick={() => _onToggle?.(value)}
      className={cx(
        "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-gray-950 disabled:pointer-events-none disabled:opacity-50",
        ITEM_VARIANTS[_variant as keyof typeof ITEM_VARIANTS] ?? ITEM_VARIANTS.default,
        ITEM_SIZES[_size as keyof typeof ITEM_SIZES] ?? ITEM_SIZES.default,
        className
      )}
      {...rest}
    >
      {children}
    </button>
  );
}

export default ToggleGroup;