{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tabs",
  "type": "registry:ui",
  "title": "Tabs",
  "description": "APG-compatible in-page tabs with controlled and uncontrolled selection, horizontal and vertical orientations, manual or automatic activation, force-mounted panels, token-backed pill and line variants, Motion-powered gliding active layer, and reduced-motion fallback.",
  "dependencies": [
    "motion@^12.43.0"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://components.dethink.co.uk/r/dethink-base.json"
  ],
  "files": [
    {
      "path": "packages/components/src/components/tabs/tabs.tsx",
      "type": "registry:file",
      "target": "~/components/dethink/components/tabs/tabs.tsx",
      "content": "import {\n  Children,\n  createContext,\n  forwardRef,\n  isValidElement,\n  useCallback,\n  useContext,\n  useId,\n  useMemo,\n  useRef,\n  useState,\n  type ButtonHTMLAttributes,\n  type FocusEvent,\n  type HTMLAttributes,\n  type KeyboardEvent,\n  type MouseEvent,\n  type ReactNode,\n  type Ref,\n} from \"react\";\nimport {\n  MotionConfig,\n  motion as motionElement,\n  useReducedMotion,\n  type Transition,\n} from \"motion/react\";\nimport { cn } from \"../../utils/cn\";\nimport { useHydrated } from \"../../utils/use-hydrated\";\n\nexport type TabsValue = string;\nexport type TabsOrientation = \"horizontal\" | \"vertical\";\nexport type TabsActivationMode = \"automatic\" | \"manual\";\nexport type TabsVariant = \"pill\" | \"line\";\nexport type TabsSize = \"sm\" | \"md\" | \"lg\";\nexport type TabsMotionPreset = \"none\" | \"subtle\" | \"standard\" | \"expressive\";\n\nexport interface TabsProps extends Omit<\n  HTMLAttributes<HTMLDivElement>,\n  \"defaultValue\"\n> {\n  activationMode?: TabsActivationMode;\n  /**\n   * Collapse horizontal triggers to their icon, revealing the label only for the\n   * selected trigger and on hover/focus. Requires each Tabs.Trigger to pass an\n   * `icon`. Vertical tabs always show their labels.\n   */\n  collapsible?: boolean;\n  defaultValue?: TabsValue;\n  disabled?: boolean;\n  loop?: boolean;\n  motionPreset?: TabsMotionPreset;\n  onValueChange?: (value: TabsValue) => void;\n  orientation?: TabsOrientation;\n  size?: TabsSize;\n  value?: TabsValue;\n  variant?: TabsVariant;\n}\n\nexport type TabsListProps = HTMLAttributes<HTMLDivElement>;\n\nexport interface TabsTriggerProps extends Omit<\n  ButtonHTMLAttributes<HTMLButtonElement>,\n  \"value\"\n> {\n  /**\n   * Leading icon rendered before the label. Stays visible when the label collapses\n   * in a collapsible Tabs, so pass a decorative icon and keep the label as children.\n   */\n  icon?: ReactNode;\n  value: TabsValue;\n}\n\nexport interface TabsPanelProps extends HTMLAttributes<HTMLDivElement> {\n  forceMount?: boolean;\n  value: TabsValue;\n}\n\ntype TabsContextValue = {\n  activationMode: TabsActivationMode;\n  collapsible: boolean;\n  contentMotionReady: boolean;\n  disabled: boolean;\n  focusValue: (value: TabsValue, source?: HTMLElement | null) => void;\n  getPanelId: (value: TabsValue) => string;\n  getTabId: (value: TabsValue) => string;\n  layoutId: string;\n  loop: boolean;\n  motionPreset: TabsMotionPreset;\n  orientation: TabsOrientation;\n  reducedMotion: boolean;\n  rootRef: React.RefObject<HTMLDivElement | null>;\n  selectValue: (value: TabsValue) => void;\n  selectedValue: TabsValue | undefined;\n  size: TabsSize;\n  tabStopValue: TabsValue | undefined;\n  transition: Transition;\n  variant: TabsVariant;\n};\n\ntype TabsPartName = \"List\" | \"Trigger\" | \"Panel\";\ntype MarkedTabsPart = {\n  [TABS_PART]?: TabsPartName;\n};\n\ntype TriggerDefinition = {\n  disabled: boolean;\n  value: TabsValue;\n};\n\nconst TABS_PART = Symbol.for(\"@dethink/tabs.part\");\nconst TabsContext = createContext<TabsContextValue | null>(null);\n\nconst tabsRootClasses = \"grid w-full min-w-0 gap-[var(--dt-space-4)]\";\n\nconst tabsListBaseClasses =\n  \"relative isolate flex min-w-0 text-sm font-medium text-muted-foreground\";\n\nconst tabsListVariantClasses: Record<TabsVariant, string> = {\n  pill: \"w-fit rounded-lg border border-border bg-muted/40 p-1 shadow-sm\",\n  line: \"w-full border-border\",\n};\n\nconst tabsListOrientationClasses: Record<\n  TabsVariant,\n  Record<TabsOrientation, string>\n> = {\n  pill: {\n    horizontal: \"flex-row items-center gap-[var(--dt-space-1)]\",\n    vertical: \"w-full flex-col items-stretch gap-[var(--dt-space-1)]\",\n  },\n  line: {\n    horizontal: \"flex-row items-center gap-[var(--dt-space-4)] border-b\",\n    vertical:\n      \"w-full flex-col items-stretch gap-[var(--dt-space-1)] border-b-0 border-e pe-[var(--dt-space-3)]\",\n  },\n};\n\nconst tabsTriggerBaseClasses =\n  \"group relative isolate inline-flex shrink-0 items-center justify-center whitespace-nowrap outline-none disabled:pointer-events-none disabled:opacity-50 data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background motion-safe:transition-[background-color,border-color,color,box-shadow,transform] motion-safe:duration-150 motion-safe:ease-out motion-safe:active:scale-[0.97] motion-reduce:transition-none\";\n\n// The content span lifts above the decorative active layer and lays the optional\n// icon and label out as a centered row, so a block-level <svg> (Tailwind preflight\n// sets svg { display:block }) sits beside its label instead of stacking above it.\nconst tabsTriggerContentClasses =\n  \"relative z-[1] inline-flex min-w-0 items-center justify-center\";\n\nconst tabsTriggerIconClasses =\n  \"grid shrink-0 place-items-center [&_svg]:size-[1.15em]\";\n\n// Static label beside an icon (non-collapsible). ps-2 gives the icon breathing room.\nconst tabsTriggerLabelClasses = \"inline-flex items-center gap-1.5 ps-2\";\n\n// Collapsible label: an animatable grid column that expands from 0fr to 1fr when the\n// trigger is selected, hovered, or keyboard-focused. The label stays mounted (only\n// clipped) so its text remains the trigger's accessible name while icon-only.\nconst tabsTriggerLabelCollapseClasses =\n  \"grid overflow-hidden motion-safe:transition-[grid-template-columns] motion-safe:duration-200 motion-safe:ease-out [grid-template-columns:0fr] group-hover:[grid-template-columns:1fr] group-focus-visible:[grid-template-columns:1fr] group-data-[selected=true]:[grid-template-columns:1fr]\";\n\nconst tabsTriggerLabelCollapseInnerClasses =\n  \"inline-flex min-w-0 items-center gap-1.5 overflow-hidden whitespace-nowrap ps-2\";\n\nconst tabsTriggerVariantClasses: Record<TabsVariant, string> = {\n  pill: \"rounded-md text-muted-foreground hover:bg-background/70 hover:text-foreground data-[selected=true]:text-primary-foreground\",\n  line: \"rounded-none border-b-2 border-transparent text-muted-foreground hover:text-foreground data-[selected=true]:text-primary\",\n};\n\nconst tabsTriggerSizeClasses: Record<TabsSize, string> = {\n  sm: \"min-h-8 px-[var(--dt-space-2-5)] text-xs\",\n  md: \"min-h-density-control px-[var(--dt-space-3)] text-sm\",\n  lg: \"min-h-11 px-[var(--dt-space-4)] text-base\",\n};\n\nconst tabsPanelClasses =\n  \"min-w-0 rounded-md text-sm leading-6 text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\";\n\nconst tabsActiveLayerVariantClasses: Record<TabsVariant, string> = {\n  pill: \"absolute inset-0 rounded-md bg-primary shadow-sm\",\n  line: \"absolute inset-x-0 -bottom-0.5 h-0.5 rounded-full bg-primary\",\n};\n\nconst tabsMotionSettings: Record<\n  TabsMotionPreset,\n  { bounce: number; duration: number }\n> = {\n  none: { bounce: 0, duration: 0 },\n  subtle: { bounce: 0, duration: 0.16 },\n  standard: { bounce: 0.04, duration: 0.22 },\n  expressive: { bounce: 0.12, duration: 0.3 },\n};\n\n// Entrance motion for the freshly revealed panel body. The offset travels along\n// the same axis the active layer glides, so the content feels tied to the tab\n// that summoned it. Distances stay small to avoid layout-shift and scrollbars.\nconst tabsPanelMotionSettings: Record<\n  TabsMotionPreset,\n  { duration: number; offset: number }\n> = {\n  none: { duration: 0, offset: 0 },\n  subtle: { duration: 0.18, offset: 4 },\n  standard: { duration: 0.24, offset: 8 },\n  expressive: { duration: 0.32, offset: 12 },\n};\n\n// A gentle ease-out curve so the body settles without overshooting its content.\nconst tabsPanelEase = [0.22, 1, 0.36, 1] as const;\n\nconst tabsPanelContentClasses = \"min-w-0\";\n\nfunction useTabsContext(component: string) {\n  const context = useContext(TabsContext);\n\n  if (!context) {\n    throw new Error(`${component} must be used within Tabs.`);\n  }\n\n  return context;\n}\n\nfunction setRef<T>(ref: Ref<T> | undefined, node: T | null) {\n  if (typeof ref === \"function\") {\n    ref(node);\n    return;\n  }\n\n  if (ref) {\n    ref.current = node;\n  }\n}\n\nfunction composeRefs<T>(...refs: Array<Ref<T> | undefined>) {\n  return (node: T | null) => {\n    for (const ref of refs) {\n      setRef(ref, node);\n    }\n  };\n}\n\nfunction markTabsPart(component: unknown, partName: TabsPartName) {\n  Object.defineProperty(component, TABS_PART, {\n    configurable: true,\n    value: partName,\n  });\n}\n\nfunction getTabsPartName(type: unknown) {\n  if (\n    typeof type === \"function\" ||\n    (typeof type === \"object\" && type !== null)\n  ) {\n    return (type as MarkedTabsPart)[TABS_PART];\n  }\n\n  return undefined;\n}\n\nfunction collectTriggers(children: ReactNode, triggers: TriggerDefinition[]) {\n  Children.forEach(children, (child) => {\n    if (!isValidElement(child)) {\n      return;\n    }\n\n    const partName = getTabsPartName(child.type);\n    const props = child.props as {\n      children?: ReactNode;\n      disabled?: boolean;\n      value?: TabsValue;\n    };\n\n    if (partName === \"Trigger\" && props.value !== undefined) {\n      triggers.push({\n        disabled: props.disabled === true,\n        value: props.value,\n      });\n      return;\n    }\n\n    if (props.children !== undefined) {\n      collectTriggers(props.children, triggers);\n    }\n  });\n}\n\nfunction getTriggerDefinitions(children: ReactNode) {\n  const triggers: TriggerDefinition[] = [];\n  collectTriggers(children, triggers);\n  return triggers;\n}\n\nfunction getIdPart(value: TabsValue) {\n  const normalized = value\n    .toLowerCase()\n    .replace(/[^a-z0-9_-]+/g, \"-\")\n    .replace(/(^-|-$)/g, \"\");\n  let hash = 0;\n\n  for (let index = 0; index < value.length; index += 1) {\n    hash = (hash * 31 + value.charCodeAt(index)) >>> 0;\n  }\n\n  return `${normalized || \"tab\"}-${hash.toString(36)}`;\n}\n\nfunction createTabsTransition(\n  motionPreset: TabsMotionPreset,\n  reducedMotion: boolean,\n): Transition {\n  const settings = reducedMotion\n    ? tabsMotionSettings.none\n    : tabsMotionSettings[motionPreset];\n\n  if (settings.duration === 0) {\n    return { duration: 0 };\n  }\n\n  return {\n    type: \"spring\",\n    visualDuration: settings.duration,\n    bounce: settings.bounce,\n  };\n}\n\nfunction getEnabledTabButtons(root: HTMLElement | null) {\n  return Array.from(\n    root?.querySelectorAll<HTMLButtonElement>(\n      'button[data-slot=\"tabs-trigger\"]:not(:disabled)',\n    ) ?? [],\n  );\n}\n\nfunction isRootRtl(root: HTMLElement | null) {\n  if (!root || typeof window === \"undefined\") {\n    return false;\n  }\n\n  const closestDirection =\n    root.getAttribute(\"dir\") ??\n    root.closest<HTMLElement>(\"[dir]\")?.getAttribute(\"dir\");\n\n  if (closestDirection) {\n    return closestDirection === \"rtl\";\n  }\n\n  return window.getComputedStyle(root).direction === \"rtl\";\n}\n\nfunction focusTabAtOffset({\n  currentTarget,\n  loop,\n  offset,\n  root,\n}: {\n  currentTarget: HTMLElement;\n  loop: boolean;\n  offset: number;\n  root: HTMLElement | null;\n}) {\n  const tabs = getEnabledTabButtons(root);\n  const currentIndex = tabs.findIndex((tab) => tab === currentTarget);\n\n  if (currentIndex === -1 || tabs.length === 0) {\n    return;\n  }\n\n  const nextIndex = currentIndex + offset;\n\n  if (!loop && (nextIndex < 0 || nextIndex >= tabs.length)) {\n    return;\n  }\n\n  tabs[(nextIndex + tabs.length) % tabs.length]?.focus();\n}\n\nfunction focusTabAtIndex(root: HTMLElement | null, index: number) {\n  const tabs = getEnabledTabButtons(root);\n  const targetIndex = index < 0 ? tabs.length + index : index;\n\n  tabs[targetIndex]?.focus();\n}\n\nexport function tabsClassNames({\n  className,\n}: Pick<TabsProps, \"className\"> = {}) {\n  return cn(tabsRootClasses, className);\n}\n\nexport function tabsListClassNames({\n  className,\n  orientation = \"horizontal\",\n  variant = \"pill\",\n}: Pick<TabsListProps, \"className\"> &\n  Pick<TabsProps, \"orientation\" | \"variant\"> = {}) {\n  return cn(\n    tabsListBaseClasses,\n    tabsListVariantClasses[variant],\n    tabsListOrientationClasses[variant][orientation],\n    className,\n  );\n}\n\nexport function tabsTriggerClassNames({\n  className,\n  size = \"md\",\n  variant = \"pill\",\n}: Pick<TabsTriggerProps, \"className\"> &\n  Pick<TabsProps, \"size\" | \"variant\"> = {}) {\n  return cn(\n    tabsTriggerBaseClasses,\n    tabsTriggerVariantClasses[variant],\n    tabsTriggerSizeClasses[size],\n    className,\n  );\n}\n\nexport function tabsPanelClassNames({\n  className,\n}: Pick<TabsPanelProps, \"className\"> = {}) {\n  return cn(tabsPanelClasses, className);\n}\n\nfunction TabsActiveLayer({\n  layoutId,\n  motionPreset,\n  reducedMotion,\n  transition,\n  variant,\n}: {\n  layoutId: string;\n  motionPreset: TabsMotionPreset;\n  reducedMotion: boolean;\n  transition: Transition;\n  variant: TabsVariant;\n}) {\n  const props = {\n    \"aria-hidden\": true,\n    \"data-motion-enabled\": reducedMotion ? undefined : \"true\",\n    \"data-motion-preset\": motionPreset,\n    \"data-reduced-motion\": reducedMotion ? \"true\" : undefined,\n    \"data-slot\": \"tabs-active-layer\",\n    className: tabsActiveLayerVariantClasses[variant],\n  } as const;\n\n  if (reducedMotion) {\n    return <span {...props} />;\n  }\n\n  return (\n    <motionElement.span\n      {...props}\n      layoutId={layoutId}\n      transition={transition}\n    />\n  );\n}\n\nconst TabsRoot = forwardRef<HTMLDivElement, TabsProps>(\n  (\n    {\n      activationMode = \"automatic\",\n      children,\n      className,\n      collapsible = false,\n      defaultValue,\n      disabled = false,\n      loop = true,\n      motionPreset = \"standard\",\n      onValueChange,\n      orientation = \"horizontal\",\n      size = \"md\",\n      value,\n      variant = \"pill\",\n      ...props\n    },\n    ref,\n  ) => {\n    const rootRef = useRef<HTMLDivElement | null>(null);\n    const generatedId = useId();\n    const controlled = Object.hasOwn(props, \"value\") || value !== undefined;\n    const triggerDefinitions = useMemo(\n      () => getTriggerDefinitions(children),\n      [children],\n    );\n    const firstEnabledValue = triggerDefinitions.find(\n      (trigger) => !trigger.disabled,\n    )?.value;\n    const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n    const [focusedValue, setFocusedValue] = useState<TabsValue | undefined>();\n    // Panels animate their body in only after mount, so the server-rendered and\n    // first client render show the initial panel content statically and visible.\n    // The entrance then plays on user-driven tab changes without an SSR flash of\n    // invisible content or a hydration mismatch.\n    const selectedValue = controlled\n      ? value\n      : (uncontrolledValue ?? firstEnabledValue);\n    const tabStopValue = focusedValue ?? selectedValue ?? firstEnabledValue;\n    const prefersReducedMotion = useReducedMotion();\n    const hasHydrated = useHydrated();\n    const contentMotionReady = hasHydrated;\n    const reducedMotion =\n      motionPreset === \"none\" || (hasHydrated && prefersReducedMotion === true);\n    const transition = useMemo(\n      () => createTabsTransition(motionPreset, reducedMotion),\n      [motionPreset, reducedMotion],\n    );\n    const rootId = `tabs-${generatedId}`;\n\n    const getTabId = useCallback(\n      (tabValue: TabsValue) => `${rootId}-trigger-${getIdPart(tabValue)}`,\n      [rootId],\n    );\n    const getPanelId = useCallback(\n      (tabValue: TabsValue) => `${rootId}-panel-${getIdPart(tabValue)}`,\n      [rootId],\n    );\n\n    const selectValue = useCallback(\n      (nextValue: TabsValue) => {\n        if (disabled) {\n          return;\n        }\n\n        const trigger = triggerDefinitions.find(\n          (definition) => definition.value === nextValue,\n        );\n\n        if (trigger?.disabled) {\n          return;\n        }\n\n        if (nextValue === selectedValue) {\n          return;\n        }\n\n        if (!controlled) {\n          setUncontrolledValue(nextValue);\n        }\n\n        onValueChange?.(nextValue);\n      },\n      [controlled, disabled, onValueChange, selectedValue, triggerDefinitions],\n    );\n\n    const focusValue = useCallback(\n      (nextValue: TabsValue, source?: HTMLElement | null) => {\n        setFocusedValue(nextValue);\n\n        if (activationMode === \"automatic\") {\n          selectValue(nextValue);\n        }\n\n        if (source) {\n          source.focus();\n        }\n      },\n      [activationMode, selectValue],\n    );\n\n    const contextValue = useMemo<TabsContextValue>(\n      () => ({\n        activationMode,\n        collapsible,\n        contentMotionReady,\n        disabled,\n        focusValue,\n        getPanelId,\n        getTabId,\n        layoutId: `${rootId}-active-layer`,\n        loop,\n        motionPreset,\n        orientation,\n        reducedMotion,\n        rootRef,\n        selectValue,\n        selectedValue,\n        size,\n        tabStopValue,\n        transition,\n        variant,\n      }),\n      [\n        activationMode,\n        collapsible,\n        contentMotionReady,\n        disabled,\n        focusValue,\n        getPanelId,\n        getTabId,\n        loop,\n        motionPreset,\n        orientation,\n        reducedMotion,\n        rootId,\n        selectValue,\n        selectedValue,\n        size,\n        tabStopValue,\n        transition,\n        variant,\n      ],\n    );\n\n    return (\n      <TabsContext.Provider value={contextValue}>\n        <MotionConfig reducedMotion={reducedMotion ? \"always\" : \"user\"}>\n          <div\n            {...props}\n            ref={composeRefs(rootRef, ref)}\n            data-slot=\"tabs\"\n            data-activation-mode={activationMode}\n            data-collapsible={collapsible ? \"true\" : undefined}\n            data-disabled={disabled ? \"true\" : undefined}\n            data-motion-preset={motionPreset}\n            data-orientation={orientation}\n            data-reduced-motion={reducedMotion ? \"true\" : undefined}\n            data-size={size}\n            data-variant={variant}\n            className={tabsClassNames({ className })}\n          >\n            {children}\n          </div>\n        </MotionConfig>\n      </TabsContext.Provider>\n    );\n  },\n);\n\nTabsRoot.displayName = \"Tabs\";\n\nexport const TabsList = forwardRef<HTMLDivElement, TabsListProps>(\n  (\n    {\n      \"aria-orientation\": ariaOrientation,\n      className,\n      children,\n      role = \"tablist\",\n      ...props\n    },\n    ref,\n  ) => {\n    const { orientation, size, variant } = useTabsContext(\"Tabs.List\");\n\n    return (\n      <div\n        {...props}\n        ref={ref}\n        aria-orientation={\n          ariaOrientation ??\n          (orientation === \"vertical\" ? \"vertical\" : undefined)\n        }\n        data-orientation={orientation}\n        data-size={size}\n        data-slot=\"tabs-list\"\n        data-variant={variant}\n        role={role}\n        className={tabsListClassNames({ className, orientation, variant })}\n      >\n        {children}\n      </div>\n    );\n  },\n);\n\nTabsList.displayName = \"TabsList\";\n\nexport const TabsTrigger = forwardRef<HTMLButtonElement, TabsTriggerProps>(\n  (\n    {\n      className,\n      children,\n      disabled: disabledProp = false,\n      icon,\n      onClick,\n      onFocus,\n      onKeyDown,\n      type = \"button\",\n      value,\n      ...props\n    },\n    ref,\n  ) => {\n    const {\n      activationMode,\n      collapsible,\n      disabled: rootDisabled,\n      focusValue,\n      getPanelId,\n      getTabId,\n      layoutId,\n      loop,\n      motionPreset,\n      orientation,\n      reducedMotion,\n      rootRef,\n      selectValue,\n      selectedValue,\n      size,\n      tabStopValue,\n      transition,\n      variant,\n    } = useTabsContext(\"Tabs.Trigger\");\n    const disabled = rootDisabled || disabledProp;\n    const selected = selectedValue === value;\n    const tabIndex = disabled ? undefined : value === tabStopValue ? 0 : -1;\n    const hasIcon = icon !== undefined && icon !== null;\n    const collapseLabel =\n      collapsible && hasIcon && orientation === \"horizontal\";\n\n    const handleFocus = (event: FocusEvent<HTMLButtonElement>) => {\n      onFocus?.(event);\n\n      if (!event.defaultPrevented && !disabled) {\n        focusValue(value);\n      }\n    };\n\n    const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n      onClick?.(event);\n\n      if (!event.defaultPrevented && !disabled) {\n        focusValue(value);\n\n        if (activationMode === \"manual\") {\n          selectValue(value);\n        }\n      }\n    };\n\n    const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n      onKeyDown?.(event);\n\n      if (event.defaultPrevented || disabled) {\n        return;\n      }\n\n      const isRtl = isRootRtl(rootRef.current);\n      const nextOffset = isRtl ? -1 : 1;\n      const previousOffset = isRtl ? 1 : -1;\n\n      if (orientation === \"horizontal\" && event.key === \"ArrowRight\") {\n        event.preventDefault();\n        focusTabAtOffset({\n          currentTarget: event.currentTarget,\n          loop,\n          offset: nextOffset,\n          root: rootRef.current,\n        });\n        return;\n      }\n\n      if (orientation === \"horizontal\" && event.key === \"ArrowLeft\") {\n        event.preventDefault();\n        focusTabAtOffset({\n          currentTarget: event.currentTarget,\n          loop,\n          offset: previousOffset,\n          root: rootRef.current,\n        });\n        return;\n      }\n\n      if (orientation === \"vertical\" && event.key === \"ArrowDown\") {\n        event.preventDefault();\n        focusTabAtOffset({\n          currentTarget: event.currentTarget,\n          loop,\n          offset: 1,\n          root: rootRef.current,\n        });\n        return;\n      }\n\n      if (orientation === \"vertical\" && event.key === \"ArrowUp\") {\n        event.preventDefault();\n        focusTabAtOffset({\n          currentTarget: event.currentTarget,\n          loop,\n          offset: -1,\n          root: rootRef.current,\n        });\n        return;\n      }\n\n      if (event.key === \"Home\") {\n        event.preventDefault();\n        focusTabAtIndex(rootRef.current, 0);\n        return;\n      }\n\n      if (event.key === \"End\") {\n        event.preventDefault();\n        focusTabAtIndex(rootRef.current, -1);\n        return;\n      }\n\n      if (\n        activationMode === \"manual\" &&\n        (event.key === \"Enter\" || event.key === \" \" || event.key === \"Spacebar\")\n      ) {\n        event.preventDefault();\n        focusValue(value);\n        selectValue(value);\n      }\n    };\n\n    return (\n      <button\n        {...props}\n        ref={ref}\n        id={getTabId(value)}\n        aria-controls={getPanelId(value)}\n        aria-selected={selected}\n        data-collapsible={collapseLabel ? \"true\" : undefined}\n        data-disabled={disabled ? \"true\" : undefined}\n        data-motion-preset={motionPreset}\n        data-orientation={orientation}\n        data-selected={selected ? \"true\" : undefined}\n        data-size={size}\n        data-slot=\"tabs-trigger\"\n        data-state={selected ? \"active\" : \"inactive\"}\n        data-value={value}\n        data-variant={variant}\n        disabled={disabled}\n        role=\"tab\"\n        tabIndex={tabIndex}\n        type={type}\n        className={tabsTriggerClassNames({ className, size, variant })}\n        onClick={handleClick}\n        onFocus={handleFocus}\n        onKeyDown={handleKeyDown}\n      >\n        {selected ? (\n          <TabsActiveLayer\n            layoutId={layoutId}\n            motionPreset={motionPreset}\n            reducedMotion={reducedMotion}\n            transition={transition}\n            variant={variant}\n          />\n        ) : null}\n        <span\n          data-slot=\"tabs-trigger-content\"\n          className={cn(\n            tabsTriggerContentClasses,\n            collapsible &&\n              hasIcon &&\n              orientation === \"vertical\" &&\n              \"w-full justify-start\",\n          )}\n        >\n          {hasIcon ? (\n            <span\n              data-slot=\"tabs-trigger-icon\"\n              className={tabsTriggerIconClasses}\n            >\n              {icon}\n            </span>\n          ) : null}\n          {hasIcon ? (\n            collapseLabel ? (\n              <span\n                data-slot=\"tabs-trigger-label\"\n                className={tabsTriggerLabelCollapseClasses}\n              >\n                <span className={tabsTriggerLabelCollapseInnerClasses}>\n                  {children}\n                </span>\n              </span>\n            ) : (\n              <span\n                data-slot=\"tabs-trigger-label\"\n                className={tabsTriggerLabelClasses}\n              >\n                {children}\n              </span>\n            )\n          ) : (\n            children\n          )}\n        </span>\n      </button>\n    );\n  },\n);\n\nTabsTrigger.displayName = \"TabsTrigger\";\n\nexport const TabsPanel = forwardRef<HTMLDivElement, TabsPanelProps>(\n  (\n    {\n      className,\n      children,\n      forceMount = false,\n      hidden: hiddenProp,\n      tabIndex,\n      value,\n      ...props\n    },\n    ref,\n  ) => {\n    const {\n      contentMotionReady,\n      getPanelId,\n      getTabId,\n      motionPreset,\n      orientation,\n      reducedMotion,\n      selectedValue,\n    } = useTabsContext(\"Tabs.Panel\");\n    const selected = selectedValue === value;\n\n    if (!selected && !forceMount) {\n      return null;\n    }\n\n    // Only non-forceMount panels remount on selection, which is what lets the\n    // entrance animation replay on each tab change. Force-mounted panels persist\n    // their DOM (and any local state), so they render statically.\n    const animateContent =\n      selected && !forceMount && !reducedMotion && motionPreset !== \"none\";\n    const panelSettings = tabsPanelMotionSettings[motionPreset];\n    const offsetAxis = orientation === \"vertical\" ? \"x\" : \"y\";\n\n    return (\n      <div\n        {...props}\n        ref={ref}\n        id={getPanelId(value)}\n        aria-labelledby={getTabId(value)}\n        data-selected={selected ? \"true\" : undefined}\n        data-slot=\"tabs-panel\"\n        data-state={selected ? \"active\" : \"inactive\"}\n        hidden={hiddenProp ?? !selected}\n        role=\"tabpanel\"\n        tabIndex={tabIndex ?? (selected ? 0 : undefined)}\n        className={tabsPanelClassNames({ className })}\n      >\n        <motionElement.div\n          data-slot=\"tabs-panel-content\"\n          className={tabsPanelContentClasses}\n          initial={\n            animateContent && contentMotionReady\n              ? { opacity: 0, [offsetAxis]: panelSettings.offset }\n              : false\n          }\n          animate={{ opacity: 1, [offsetAxis]: 0 }}\n          transition={{\n            duration: animateContent ? panelSettings.duration : 0,\n            ease: tabsPanelEase,\n          }}\n        >\n          {children}\n        </motionElement.div>\n      </div>\n    );\n  },\n);\n\nTabsPanel.displayName = \"TabsPanel\";\n\nmarkTabsPart(TabsList, \"List\");\nmarkTabsPart(TabsTrigger, \"Trigger\");\nmarkTabsPart(TabsPanel, \"Panel\");\n\ntype TabsComponent = typeof TabsRoot & {\n  List: typeof TabsList;\n  Panel: typeof TabsPanel;\n  Trigger: typeof TabsTrigger;\n};\n\nexport const Tabs = Object.assign(TabsRoot, {\n  List: TabsList,\n  Panel: TabsPanel,\n  Trigger: TabsTrigger,\n}) as TabsComponent;\n"
    },
    {
      "path": "packages/components/src/components/tabs/index.ts",
      "type": "registry:file",
      "target": "~/components/dethink/components/tabs/index.ts",
      "content": "export {\n  Tabs,\n  TabsList,\n  TabsPanel,\n  TabsTrigger,\n  tabsClassNames,\n  tabsListClassNames,\n  tabsPanelClassNames,\n  tabsTriggerClassNames,\n  type TabsActivationMode,\n  type TabsListProps,\n  type TabsMotionPreset,\n  type TabsOrientation,\n  type TabsPanelProps,\n  type TabsProps,\n  type TabsSize,\n  type TabsTriggerProps,\n  type TabsValue,\n  type TabsVariant,\n} from \"./tabs\";\n"
    },
    {
      "path": "packages/components/src/utils/cn.ts",
      "type": "registry:file",
      "target": "~/components/dethink/utils/cn.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n"
    }
  ]
}
