{
  "name": "toggle-group",
  "type": "registry:ui",
  "description": "Group of two-state buttons, single or multiple pressed",
  "files": [
    {
      "path": "ui/toggle-group.tsx",
      "type": "registry:ui",
      "content": "import { fv } from \"@facet-ui/react-variants\";\nimport {\n  getPassthroughProps,\n  type PassthroughProps,\n  React,\n  toSlotProps,\n  useControllableState,\n} from \"@lattice-ui/react-runtime\";\nimport { ToggleGroup as ToggleGroupPrimitive } from \"@lattice-ui/react-toggle-group\";\nimport { TextSlot } from \"~/lib/text\";\nimport { type ClassName, cn } from \"~/lib/utils\";\n\n/**\n * The group's value is mirrored here with `useControllableState` — the same\n * hook the primitive uses — because Lattice keeps its context private and each\n * item's surface changes with whether it is pressed. The primitive is then\n * driven controlled, so there is exactly one copy of the state, and a Facet\n * context hands each item its answer.\n *\n * One recipe object rather than three exports: every exported name costs a\n * Luau register once Vela inlines its runtime. See\n * docs/decisions/luau-register-limit.md.\n */\nexport const toggleGroupVariants = {\n  root: fv(\"flex-row items-center gap-1 w-fit h-fit\"),\n  item: fv(\n    \"flex-row items-center justify-center gap-2 h-9 w-fit min-w-9 px-2 rounded-md transition duration-150 hover:bg-muted\",\n  ),\n  label: fv(\"whitespace-nowrap text-sm font-medium text-foreground\"),\n};\n\ntype ToggleGroupContextValue = {\n  isPressed: (value: string) => boolean;\n  disabled: boolean;\n};\n\nconst ToggleGroupContext = React.createContext<ToggleGroupContextValue | undefined>(undefined);\n\nexport type ToggleGroupProps = {\n  /** `single` keeps at most one item pressed; `multiple` lets them accumulate. */\n  type: \"single\" | \"multiple\";\n  value?: string | string[];\n  defaultValue?: string | string[];\n  onValueChange?: (value: string | string[] | undefined) => void;\n  disabled?: boolean;\n  className?: ClassName;\n  children?: React.ReactNode;\n} & PassthroughProps<Frame>;\n\nexport type ToggleGroupItemProps = {\n  value: string;\n  disabled?: boolean;\n  Text?: string;\n  className?: ClassName;\n  children?: React.ReactNode;\n};\n\nconst ROOT_OWN_PROPS = [\"type\", \"value\", \"defaultValue\", \"onValueChange\", \"disabled\", \"className\", \"children\"] as const;\n\nexport function ToggleGroup(props: ToggleGroupProps) {\n  const [value, setValue] = useControllableState<string | string[] | undefined>({\n    value: props.value,\n    defaultValue: props.defaultValue,\n    onChange: props.onValueChange,\n  });\n\n  const disabled = props.disabled === true;\n\n  const isPressed = React.useCallback(\n    (itemValue: string) => {\n      if (typeIs(value, \"table\")) {\n        return (value as string[]).includes(itemValue);\n      }\n      return value === itemValue;\n    },\n    [value],\n  );\n\n  const contextValue = React.useMemo(() => ({ isPressed, disabled }), [disabled, isPressed]);\n\n  // `className` is written out as an attribute on both branches rather than\n  // tucked into a shared spread: Vela rewrites the call site it can *see*, and\n  // a className hidden inside a spread would reach the primitive as a raw prop\n  // instead of being resolved.\n  //\n  // The primitive's props are a discriminated union over `type`, and the\n  // mirrored value is the union's width — so one branch per arm keeps the\n  // narrowing honest instead of casting across it.\n  const className = toggleGroupVariants.root({ className: props.className });\n  const passthrough = toSlotProps(getPassthroughProps<Frame>(props, ROOT_OWN_PROPS));\n\n  return (\n    <ToggleGroupContext.Provider value={contextValue}>\n      {props.type === \"multiple\" ? (\n        <ToggleGroupPrimitive.Root\n          className={className}\n          type=\"multiple\"\n          value={typeIs(value, \"table\") ? (value as string[]) : []}\n          onValueChange={setValue}\n          disabled={disabled}\n          {...passthrough}\n        >\n          {props.children}\n        </ToggleGroupPrimitive.Root>\n      ) : (\n        <ToggleGroupPrimitive.Root\n          className={className}\n          type=\"single\"\n          value={typeIs(value, \"string\") ? value : undefined}\n          onValueChange={setValue}\n          disabled={disabled}\n          {...passthrough}\n        >\n          {props.children}\n        </ToggleGroupPrimitive.Root>\n      )}\n    </ToggleGroupContext.Provider>\n  );\n}\n\nexport function ToggleGroupItem(props: ToggleGroupItemProps) {\n  const group = React.useContext(ToggleGroupContext);\n  if (group === undefined) {\n    error(\"[ToggleGroupItem] must be rendered inside a ToggleGroup.\");\n  }\n\n  const pressed = group.isPressed(props.value);\n  const disabled = group.disabled || props.disabled === true;\n\n  return (\n    <ToggleGroupPrimitive.Item\n      className={toggleGroupVariants.item({\n        className: cn(pressed && \"bg-accent hover:bg-accent\", disabled && \"opacity-50\", props.className),\n      })}\n      disabled={props.disabled}\n      value={props.value}\n    >\n      <TextSlot\n        Text={props.Text}\n        TextTransparency={disabled ? 0.5 : 0}\n        className={cn(toggleGroupVariants.label(), pressed && \"text-accent-foreground\")}\n      >\n        {props.children}\n      </TextSlot>\n    </ToggleGroupPrimitive.Item>\n  );\n}\n"
    }
  ],
  "registryDependencies": [
    "utils",
    "text"
  ],
  "dependencies": [
    "@facet-ui/react-variants@^0.1.1",
    "@lattice-ui/react-runtime@^0.8.0",
    "@lattice-ui/react-toggle-group@^0.8.0"
  ],
  "tokens": [
    "muted",
    "accent",
    "accent-foreground",
    "foreground"
  ]
}
