{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"toggle","title":"Toggle","description":"Base UI-backed pressed-state action.","dependencies":["@base-ui/react@1.7.0","class-variance-authority@0.7.1"],"registryDependencies":["@siteplane/base"],"files":[{"path":"packages/ui/src/components/toggle/toggle.tsx","content":"\"use client\";\n\nimport { Toggle as TogglePrimitive } from \"@base-ui/react/toggle\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport {\n  siteplaneUIDefaults,\n  useResolvedControlSize,\n} from \"../../system/provider/siteplane-ui-provider\";\nimport { cn, type WithStringClassName } from \"../../system/utils/cn\";\nimport { baseClass, slotClass } from \"../../system/utils/slot-class\";\nimport type { KitToggleProps } from \"./toggle-internal\";\n\n// The kit stylesheet owns the Toggle's cursor and its disabled fade\n// (design-rework.css), so a cursor or opacity utility in `className` wins.\nexport const toggleVariants = cva(\n  \"shrink-0 select-none justify-center whitespace-nowrap before:pointer-events-none before:absolute pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 data-pressed:text-accent-foreground [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg]:-mx-0.5 [&_svg]:shrink-0\",\n  {\n    defaultVariants: {\n      size: siteplaneUIDefaults.controlSize,\n      variant: \"default\",\n    },\n    variants: {\n      size: {\n        md: \"\",\n        lg: \"\",\n        sm: \"\",\n        // design-rework.css sets the control scale's xl icon and 16 px label.\n        xl: \"\",\n      },\n      padding: {\n        // 12 px at the sides: the [data-padding=\"comfortable\"] rule in\n        // design-rework.css.\n        comfortable: \"\",\n        default: null,\n        icon: \"\",\n      },\n      variant: {\n        default: \"\",\n        // design-rework.css draws the outline edge as an inset rim.\n        outline: \"\",\n      },\n    },\n  },\n);\n\n// ToggleGroup renders its toggles with the internal group profile.\nconst toggleGroupProfileClassName =\n  \"focus-visible:z-10 in-data-[orientation=horizontal]:pointer-coarse:after:min-w-auto in-data-[orientation=vertical]:pointer-coarse:after:min-h-auto\";\n\nexport function Toggle(\n  toggleProps: WithStringClassName<TogglePrimitive.Props> &\n    VariantProps<typeof toggleVariants> & {\n      /**\n       * Lifts the icon once each time the toggle turns on: up and back with a\n       * slight tilt, for a reaction such as a like. The icon is the toggle's\n       * first child; reduced motion keeps it still.\n       */\n      lift?: boolean;\n    },\n) {\n  // ToggleGroup and the theme toggles pass their internal profiles through\n  // KitToggle (toggle-internal.ts), the same function.\n  const {\n    className,\n    lift = false,\n    onAnimationEnd,\n    onPressedChange,\n    padding = \"default\",\n    profile = \"default\",\n    variant,\n    size,\n    ...props\n  } = toggleProps as KitToggleProps;\n  const resolvedSize = useResolvedControlSize(size);\n  // The lift plays when the toggle turns on, not when it renders pressed, and\n  // the attribute clears when it ends, so the next press plays it again\n  // (motion.css).\n  const [lifting, setLifting] = React.useState(false);\n  return (\n    <TogglePrimitive\n      className={cn(\n        slotClass(\"toggle\", props),\n        baseClass(\"toggle\", props),\n        toggleVariants({ padding, size: resolvedSize, variant }),\n        profile === \"group\" && toggleGroupProfileClassName,\n        \"sp-toggle-motion\",\n        className,\n      )}\n      data-foundation=\"toggle\"\n      data-lift={lift ? (lifting ? \"on\" : \"\") : undefined}\n      data-padding={padding}\n      data-profile={profile}\n      data-size={resolvedSize}\n      data-slot=\"toggle\"\n      data-variant={variant ?? \"default\"}\n      onAnimationEnd={(event) => {\n        if (event.animationName === \"sp-toggle-lift\") setLifting(false);\n        onAnimationEnd?.(event);\n      }}\n      onPressedChange={(pressed, eventDetails) => {\n        if (lift && pressed) setLifting(true);\n        onPressedChange?.(pressed, eventDetails);\n      }}\n      {...props}\n    />\n  );\n}\n\nexport { TogglePrimitive };\n","type":"registry:ui","target":"~/src/siteplane/components/toggle/toggle.tsx"},{"path":"packages/ui/src/components/toggle/toggle-internal.ts","content":"import type * as React from \"react\";\n\nimport { Toggle } from \"./toggle\";\n\n/*\n * Kit-internal Toggle. Not public API: the toggle index does not export this\n * module, and its names and profiles may change in any release. ToggleGroup\n * renders its toggles with the group profile, and the theme toggles with the\n * theme profile.\n */\nexport type ToggleProfile = \"default\" | \"group\" | \"theme\";\n\nexport type KitToggleProps = React.ComponentProps<typeof Toggle> & {\n  profile?: ToggleProfile;\n};\n\n/** Toggle with the kit's composition profiles; the same component. */\nexport const KitToggle = Toggle as (\n  props: KitToggleProps,\n) => React.ReactElement;\n","type":"registry:ui","target":"~/src/siteplane/components/toggle/toggle-internal.ts"},{"path":"packages/ui/src/components/toggle/index.ts","content":"export * from \"./toggle\";\n","type":"registry:ui","target":"~/src/siteplane/components/toggle/index.ts"}],"type":"registry:ui","docs":"https://ui.siteplane.io/docs-markdown/components/toggle.md","categories":["Actions"],"meta":{"avoidWhen":["Avoid for a setting in a form; use Switch or Checkbox.","Avoid for a single action; use Button."],"description":"Base UI-backed pressed-state action.","knownLimitations":["Toggle submits no boolean form value; use Checkbox or Switch, or serialize the state yourself."],"providerNotes":[],"releaseStatus":"stable","searchTerms":["toggle"],"useWhen":["Use for a button that stays pressed or unpressed, such as bold in a toolbar."]}}