{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "horizontal-accordion",
  "type": "registry:ui",
  "title": "HorizontalAccordion",
  "description": "Fixed-height horizontal band of always-visible blades where one panel expands at a time, with a Motion-powered gliding active layer, choreographed panel content, roving keyboard navigation, RTL-aware arrows, and a container-driven compact layout.",
  "dependencies": [
    "motion@^12.43.0"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://components.dethink.co.uk/r/dethink-base.json"
  ],
  "files": [
    {
      "path": "packages/components/src/components/horizontal-accordion/horizontal-accordion.tsx",
      "type": "registry:file",
      "target": "~/components/dethink/components/horizontal-accordion/horizontal-accordion.tsx",
      "content": "import {\n  Children,\n  createContext,\n  forwardRef,\n  isValidElement,\n  useCallback,\n  useContext,\n  useEffect,\n  useId,\n  useMemo,\n  useRef,\n  useState,\n  version as reactVersion,\n  type ButtonHTMLAttributes,\n  type CSSProperties,\n  type HTMLAttributes,\n  type ReactNode,\n} from \"react\";\nimport {\n  AnimatePresence,\n  LayoutGroup,\n  MotionConfig,\n  motion,\n  type Transition,\n} from \"motion/react\";\nimport { cn } from \"../../utils/cn\";\n\ndeclare const process:\n  | {\n      env?: {\n        NODE_ENV?: string;\n      };\n    }\n  | undefined;\n\nexport type HorizontalAccordionValue = string | undefined;\n\nexport type HorizontalAccordionAnimation = {\n  duration?: number;\n  easing?: string;\n  content?: boolean;\n};\n\nexport type HorizontalAccordionActivationMode = \"manual\" | \"automatic\";\n\nexport interface HorizontalAccordionProps extends HTMLAttributes<HTMLDivElement> {\n  value?: HorizontalAccordionValue;\n  defaultValue?: HorizontalAccordionValue;\n  onValueChange?: (value: HorizontalAccordionValue) => void;\n  collapsible?: boolean;\n  activationMode?: HorizontalAccordionActivationMode;\n  bladeWidth?: number;\n  height?: number;\n  compactBreakpoint?: number;\n  animation?: HorizontalAccordionAnimation;\n  unmountInactivePanels?: boolean;\n}\n\nexport type HorizontalAccordionLayout = \"default\" | \"compact\";\n\nexport interface HorizontalAccordionItemProps extends HTMLAttributes<HTMLDivElement> {\n  value: string;\n}\n\nexport type HorizontalAccordionBladeIconPosition =\n  \"start\" | \"end\" | \"top\" | \"bottom\";\n\nexport interface HorizontalAccordionBladeProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n  iconPosition?: HorizontalAccordionBladeIconPosition;\n}\n\nexport type HorizontalAccordionBladeIconProps = HTMLAttributes<HTMLSpanElement>;\n\nexport type HorizontalAccordionBladeLabelOrientation = \"rotated\" | \"vertical\";\nexport type HorizontalAccordionBladeLabelDirection =\n  \"bottom-to-top\" | \"top-to-bottom\";\n\nexport interface HorizontalAccordionBladeLabelProps extends HTMLAttributes<HTMLSpanElement> {\n  orientation?: HorizontalAccordionBladeLabelOrientation;\n  direction?: HorizontalAccordionBladeLabelDirection;\n}\n\nexport type HorizontalAccordionPanelProps = HTMLAttributes<HTMLDivElement>;\n\ntype AccordionMotionConfig = {\n  activeLayerTransition: Transition;\n  contentEnabled: boolean;\n  contentEnterTransition: Transition;\n  contentExitTransition: Transition;\n};\n\ntype AccordionContextValue = {\n  activationMode: HorizontalAccordionActivationMode;\n  activeValue: HorizontalAccordionValue;\n  layout: HorizontalAccordionLayout;\n  motionConfig: AccordionMotionConfig;\n  tabStopValue: HorizontalAccordionValue;\n  unmountInactivePanels: boolean;\n  registerBlade: (value: string, disabled: boolean) => () => void;\n  setActiveValue: (value: string) => void;\n  setFocusedValue: (value: string) => void;\n};\n\ntype BladeRegistryEntry = {\n  disabled: boolean;\n};\n\ntype ItemContextValue = {\n  active: boolean;\n  bladeId: string;\n  panelId: string;\n  value: string;\n};\n\n// React 18 serializes unknown attributes; React 19 supports boolean inert.\nconst inertAttribute = (\n  Number.parseInt(reactVersion, 10) < 19 ? \"\" : true\n) as true;\n\nconst DEFAULT_BLADE_WIDTH = 72;\nconst DEFAULT_HEIGHT = 420;\nconst DEFAULT_COMPACT_BREAKPOINT = 640;\nconst DEFAULT_ANIMATION: Required<HorizontalAccordionAnimation> = {\n  duration: 260,\n  easing: \"cubic-bezier(0.2, 0, 0, 1)\",\n  content: true,\n};\nconst ACCORDION_PART = Symbol.for(\"@dethink/horizontal-accordion.part\");\n\nconst AccordionContext = createContext<AccordionContextValue | null>(null);\nconst ItemContext = createContext<ItemContextValue | null>(null);\n\ntype AccordionPartName = \"Item\" | \"Blade\" | \"Panel\";\ntype MarkedAccordionPart = {\n  [ACCORDION_PART]?: AccordionPartName;\n};\n\ntype HorizontalAccordionStyle = CSSProperties & {\n  \"--horizontal-accordion-blade-width\"?: string;\n  \"--horizontal-accordion-height\"?: string;\n  \"--horizontal-accordion-compact-breakpoint\"?: string;\n  \"--horizontal-accordion-item-count\"?: string;\n  \"--horizontal-accordion-duration\"?: string;\n  \"--horizontal-accordion-easing\"?: string;\n};\n\nconst horizontalAccordionRootClasses =\n  \"group/horizontal-accordion relative isolate flex h-[var(--horizontal-accordion-height)] min-h-0 w-full overflow-hidden text-foreground data-[layout=compact]:grid data-[layout=compact]:h-auto data-[layout=compact]:min-h-[var(--horizontal-accordion-height)] data-[layout=compact]:grid-cols-[repeat(var(--horizontal-accordion-item-count),minmax(0,1fr))] data-[layout=compact]:grid-rows-[minmax(0,1fr)_auto]\";\n\nconst horizontalAccordionItemClasses =\n  \"flex h-full min-h-0 min-w-[var(--horizontal-accordion-blade-width)] shrink-0 grow-0 basis-[var(--horizontal-accordion-blade-width)] motion-safe:transition-[flex-basis,flex-grow,min-width] motion-safe:duration-[var(--horizontal-accordion-duration)] motion-safe:ease-[var(--horizontal-accordion-easing)] motion-reduce:transition-none data-[state=active]:min-w-[min(100%,calc(var(--horizontal-accordion-blade-width)+16rem))] data-[state=active]:shrink data-[state=active]:grow data-[state=active]:basis-0 data-[layout=compact]:contents\";\n\nconst horizontalAccordionBladeClasses =\n  \"group/horizontal-accordion-blade relative flex h-full w-[var(--horizontal-accordion-blade-width)] min-w-[var(--horizontal-accordion-blade-width)] shrink-0 grow-0 basis-[var(--horizontal-accordion-blade-width)] cursor-pointer flex-col items-center justify-between gap-[var(--dt-space-3)] overflow-hidden border-e border-border bg-muted px-[var(--dt-space-2)] py-[var(--dt-space-4)] text-muted-foreground outline-none motion-safe:transition-colors motion-safe:duration-[var(--horizontal-accordion-duration)] motion-safe:ease-[var(--horizontal-accordion-easing)] motion-reduce:transition-none after:pointer-events-none after:absolute after:inset-1 after:z-[3] after:rounded-sm after:border-2 after:border-current after:opacity-0 focus-visible:after:opacity-100 data-[state=active]:text-primary-foreground motion-reduce:data-[state=active]:bg-primary disabled:cursor-not-allowed disabled:opacity-50 data-[layout=compact]:row-start-2 data-[layout=compact]:h-auto data-[layout=compact]:w-auto data-[layout=compact]:min-w-0 data-[layout=compact]:min-h-[var(--horizontal-accordion-blade-width)] data-[layout=compact]:basis-auto data-[layout=compact]:border-e-0 data-[layout=compact]:border-t data-[layout=compact]:p-[var(--dt-space-3)] [&>:not([data-slot=horizontal-accordion-blade-active-layer])]:relative [&>:not([data-slot=horizontal-accordion-blade-active-layer])]:z-[2]\";\n\nconst horizontalAccordionBladeActiveLayerClasses =\n  \"pointer-events-none absolute inset-0 z-[1] bg-primary\";\n\nconst horizontalAccordionBladeIconClasses =\n  \"pointer-events-none order-1 inline-flex items-center justify-center [&:only-child]:my-auto group-data-[icon-position=end]/horizontal-accordion-blade:order-3\";\n\nconst horizontalAccordionBladeLabelClasses =\n  \"pointer-events-none order-2 inline-flex min-w-0 flex-1 items-center justify-center whitespace-nowrap text-sm font-semibold data-[layout=default]:data-[orientation=rotated]:data-[direction=bottom-to-top]:-rotate-90 data-[layout=default]:data-[orientation=rotated]:data-[direction=top-to-bottom]:rotate-90 data-[layout=default]:data-[orientation=vertical]:[writing-mode:vertical-rl] data-[layout=default]:data-[orientation=vertical]:data-[direction=bottom-to-top]:rotate-180 data-[layout=compact]:whitespace-normal\";\n\nconst horizontalAccordionPanelClasses =\n  \"min-h-0 min-w-0 flex-1 overflow-hidden [contain:paint] data-[layout=compact]:col-span-full data-[layout=compact]:row-start-1\";\n\nexport function horizontalAccordionClassNames({\n  className,\n}: Pick<HorizontalAccordionProps, \"className\"> = {}) {\n  return cn(horizontalAccordionRootClasses, className);\n}\n\nexport function horizontalAccordionItemClassNames({\n  className,\n}: Pick<HorizontalAccordionItemProps, \"className\"> = {}) {\n  return cn(horizontalAccordionItemClasses, className);\n}\n\nexport function horizontalAccordionBladeClassNames({\n  className,\n}: Pick<HorizontalAccordionBladeProps, \"className\"> = {}) {\n  return cn(horizontalAccordionBladeClasses, className);\n}\n\nexport function horizontalAccordionBladeIconClassNames({\n  className,\n}: Pick<HorizontalAccordionBladeIconProps, \"className\"> = {}) {\n  return cn(horizontalAccordionBladeIconClasses, className);\n}\n\nexport function horizontalAccordionBladeLabelClassNames({\n  className,\n}: Pick<HorizontalAccordionBladeLabelProps, \"className\"> = {}) {\n  return cn(horizontalAccordionBladeLabelClasses, className);\n}\n\nexport function horizontalAccordionPanelClassNames({\n  className,\n}: Pick<HorizontalAccordionPanelProps, \"className\"> = {}) {\n  return cn(horizontalAccordionPanelClasses, className);\n}\n\nfunction useAccordionContext(component: string) {\n  const context = useContext(AccordionContext);\n\n  if (!context) {\n    throw new Error(`${component} must be used within HorizontalAccordion.`);\n  }\n\n  return context;\n}\n\nfunction useItemContext(component: string) {\n  const context = useContext(ItemContext);\n\n  if (!context) {\n    throw new Error(\n      `${component} must be used within HorizontalAccordion.Item.`,\n    );\n  }\n\n  return context;\n}\n\nfunction isDevelopment() {\n  return (\n    typeof process === \"undefined\" || process.env?.NODE_ENV !== \"production\"\n  );\n}\n\nfunction getAccordionPartName(type: unknown) {\n  if (\n    typeof type === \"function\" ||\n    (typeof type === \"object\" && type !== null)\n  ) {\n    return (type as MarkedAccordionPart)[ACCORDION_PART];\n  }\n\n  return undefined;\n}\n\nfunction countDirectChildrenOfPart(\n  children: ReactNode,\n  partName: AccordionPartName,\n  type: unknown,\n) {\n  let count = 0;\n\n  Children.forEach(children, (child) => {\n    if (\n      isValidElement(child) &&\n      (child.type === type || getAccordionPartName(child.type) === partName)\n    ) {\n      count += 1;\n    }\n  });\n\n  return count;\n}\n\nfunction getDirectItemValues(children: ReactNode) {\n  const values: string[] = [];\n\n  Children.forEach(children, (child) => {\n    if (\n      isValidElement(child) &&\n      (child.type === HorizontalAccordionItem ||\n        getAccordionPartName(child.type) === \"Item\")\n    ) {\n      values.push((child.props as HorizontalAccordionItemProps).value);\n    }\n  });\n\n  return values;\n}\n\nfunction validateRootComposition(children: ReactNode) {\n  if (!isDevelopment()) {\n    return;\n  }\n\n  const seen = new Set<string>();\n\n  for (const itemValue of getDirectItemValues(children)) {\n    if (seen.has(itemValue)) {\n      throw new Error(\n        `Duplicate HorizontalAccordion.Item value \"${itemValue}\".`,\n      );\n    }\n\n    seen.add(itemValue);\n  }\n}\n\nfunction validateItemComposition(children: ReactNode, value: string) {\n  if (!isDevelopment()) {\n    return;\n  }\n\n  const bladeCount = countDirectChildrenOfPart(\n    children,\n    \"Blade\",\n    HorizontalAccordionBlade,\n  );\n  const panelCount = countDirectChildrenOfPart(\n    children,\n    \"Panel\",\n    HorizontalAccordionPanel,\n  );\n\n  if (bladeCount !== 1 || panelCount !== 1) {\n    throw new Error(\n      `HorizontalAccordion.Item \"${value}\" must contain exactly one Blade and one Panel.`,\n    );\n  }\n}\n\nfunction markAccordionPart(component: unknown, partName: AccordionPartName) {\n  Object.defineProperty(component, ACCORDION_PART, {\n    configurable: true,\n    value: partName,\n  });\n}\n\nfunction getMotionEase(easing: string) {\n  return easing.trim().toLowerCase() === \"linear\"\n    ? (\"linear\" as const)\n    : ([0.2, 0, 0, 1] as [number, number, number, number]);\n}\n\nfunction createMotionConfig(\n  animation: Required<HorizontalAccordionAnimation>,\n): AccordionMotionConfig {\n  const ease = getMotionEase(animation.easing);\n  const layoutDuration = Math.max(1, animation.duration);\n  const colorDuration = Math.max(100, Math.round(animation.duration * 0.8));\n\n  return {\n    activeLayerTransition: {\n      layout: {\n        duration: layoutDuration / 1000,\n        ease,\n      },\n      backgroundColor: {\n        duration: colorDuration / 1000,\n        ease,\n      },\n    },\n    contentEnabled: animation.content,\n    contentEnterTransition: {\n      delay: Math.min(Math.round(animation.duration * 0.55), 160) / 1000,\n      duration: Math.max(Math.round(animation.duration * 0.75), 140) / 1000,\n      ease,\n    },\n    contentExitTransition: {\n      duration: Math.max(Math.round(animation.duration * 0.45), 120) / 1000,\n      ease,\n    },\n  };\n}\n\nfunction renderBladeChildren(children: ReactNode) {\n  return Children.map(children, (child) => {\n    if (typeof child === \"string\" || typeof child === \"number\") {\n      return (\n        <span\n          className=\"pointer-events-none order-2 inline-flex min-w-0 flex-1 items-center justify-center text-sm font-semibold whitespace-nowrap\"\n          data-slot=\"horizontal-accordion-blade-content\"\n        >\n          {child}\n        </span>\n      );\n    }\n\n    return child;\n  });\n}\n\nconst HorizontalAccordionRoot = forwardRef<\n  HTMLDivElement,\n  HorizontalAccordionProps\n>((props, ref) => {\n  const {\n    value,\n    defaultValue,\n    onValueChange,\n    collapsible = true,\n    activationMode = \"manual\",\n    bladeWidth = DEFAULT_BLADE_WIDTH,\n    height = DEFAULT_HEIGHT,\n    compactBreakpoint = DEFAULT_COMPACT_BREAKPOINT,\n    animation,\n    unmountInactivePanels = false,\n    className,\n    children,\n    style,\n    ...rootProps\n  } = props;\n  const [uncontrolledValue, setUncontrolledValue] =\n    useState<HorizontalAccordionValue>(defaultValue);\n  const controlled = Object.hasOwn(props, \"value\");\n  const activeValue = controlled ? value : uncontrolledValue;\n  const itemValues = useMemo(() => getDirectItemValues(children), [children]);\n  const [focusedValue, setFocusedValue] =\n    useState<HorizontalAccordionValue>(defaultValue);\n  const [bladeRegistry, setBladeRegistry] = useState(\n    () => new Map<string, BladeRegistryEntry>(),\n  );\n  const layoutGroupId = useId();\n  const rootRef = useRef<HTMLDivElement | null>(null);\n  const [layout, setLayout] = useState<HorizontalAccordionLayout>(\"default\");\n  const mergedAnimation = useMemo(\n    () => ({ ...DEFAULT_ANIMATION, ...animation }),\n    [animation],\n  );\n  const motionConfig = useMemo(\n    () => createMotionConfig(mergedAnimation),\n    [mergedAnimation],\n  );\n  const mergedRef = useCallback(\n    (node: HTMLDivElement | null) => {\n      rootRef.current = node;\n\n      if (typeof ref === \"function\") {\n        ref(node);\n      } else if (ref) {\n        ref.current = node;\n      }\n    },\n    [ref],\n  );\n\n  useEffect(() => {\n    const root = rootRef.current;\n\n    if (!root) {\n      return;\n    }\n\n    const updateLayout = (width: number) => {\n      setLayout(\n        width > 0 && width <= compactBreakpoint ? \"compact\" : \"default\",\n      );\n    };\n    const initialWidth = root.getBoundingClientRect().width;\n\n    if (initialWidth > 0) {\n      updateLayout(initialWidth);\n    }\n\n    if (typeof ResizeObserver === \"undefined\") {\n      return;\n    }\n\n    const observer = new ResizeObserver((entries) => {\n      const [entry] = entries;\n\n      if (entry) {\n        updateLayout(entry.contentRect.width);\n      }\n    });\n\n    observer.observe(root);\n\n    return () => {\n      observer.disconnect();\n    };\n  }, [compactBreakpoint]);\n  const rootStyle: HorizontalAccordionStyle = {\n    \"--horizontal-accordion-blade-width\": `${bladeWidth}px`,\n    \"--horizontal-accordion-height\": `${height}px`,\n    \"--horizontal-accordion-compact-breakpoint\": `${compactBreakpoint}px`,\n    \"--horizontal-accordion-item-count\": `${Math.max(itemValues.length, 1)}`,\n    \"--horizontal-accordion-duration\": `${mergedAnimation.duration}ms`,\n    \"--horizontal-accordion-easing\": mergedAnimation.easing,\n    ...style,\n  };\n\n  validateRootComposition(children);\n\n  const registerBlade = useCallback((value: string, disabled: boolean) => {\n    setBladeRegistry((current) => {\n      if (current.get(value)?.disabled === disabled) return current;\n      return new Map(current).set(value, { disabled });\n    });\n    return () =>\n      setBladeRegistry((current) => {\n        if (!current.has(value)) return current;\n        const next = new Map(current);\n        next.delete(value);\n        return next;\n      });\n  }, []);\n\n  const enabledItemValues = useMemo(\n    () =>\n      itemValues.filter((itemValue) => !bladeRegistry.get(itemValue)?.disabled),\n    [bladeRegistry, itemValues],\n  );\n\n  const tabStopValue =\n    focusedValue && enabledItemValues.includes(focusedValue)\n      ? focusedValue\n      : activeValue && enabledItemValues.includes(activeValue)\n        ? activeValue\n        : enabledItemValues[0];\n\n  const setActiveValue = useCallback(\n    (nextValue: string) => {\n      const nextActiveValue =\n        activeValue === nextValue && collapsible ? undefined : nextValue;\n\n      if (nextActiveValue === activeValue) {\n        return;\n      }\n\n      if (!controlled) {\n        setUncontrolledValue(nextActiveValue);\n      }\n\n      onValueChange?.(nextActiveValue);\n    },\n    [activeValue, collapsible, controlled, onValueChange],\n  );\n\n  const contextValue = useMemo<AccordionContextValue>(\n    () => ({\n      activationMode,\n      activeValue,\n      layout,\n      motionConfig,\n      tabStopValue,\n      unmountInactivePanels,\n      registerBlade,\n      setActiveValue,\n      setFocusedValue,\n    }),\n    [\n      activationMode,\n      activeValue,\n      layout,\n      motionConfig,\n      registerBlade,\n      setActiveValue,\n      tabStopValue,\n      unmountInactivePanels,\n    ],\n  );\n\n  return (\n    <AccordionContext.Provider value={contextValue}>\n      <MotionConfig reducedMotion=\"user\">\n        <LayoutGroup id={layoutGroupId}>\n          <div\n            role=\"group\"\n            {...rootProps}\n            ref={mergedRef}\n            data-slot=\"horizontal-accordion\"\n            data-content-animation={motionConfig.contentEnabled ? \"on\" : \"off\"}\n            data-layout={layout}\n            className={horizontalAccordionClassNames({ className })}\n            style={rootStyle}\n          >\n            {children}\n          </div>\n        </LayoutGroup>\n      </MotionConfig>\n    </AccordionContext.Provider>\n  );\n});\n\nHorizontalAccordionRoot.displayName = \"HorizontalAccordion\";\n\nexport const HorizontalAccordionItem = forwardRef<\n  HTMLDivElement,\n  HorizontalAccordionItemProps\n>(({ value, className, children, ...props }, ref) => {\n  const { activeValue, layout } = useAccordionContext(\n    \"HorizontalAccordion.Item\",\n  );\n  const generatedId = useId();\n  const active = activeValue === value;\n  const bladeId = `horizontal-accordion-blade-${generatedId}`;\n  const panelId = `horizontal-accordion-panel-${generatedId}`;\n  const itemContextValue = useMemo<ItemContextValue>(\n    () => ({ active, bladeId, panelId, value }),\n    [active, bladeId, panelId, value],\n  );\n\n  validateItemComposition(children, value);\n\n  return (\n    <ItemContext.Provider value={itemContextValue}>\n      <div\n        {...props}\n        ref={ref}\n        data-slot=\"horizontal-accordion-item\"\n        data-state={active ? \"active\" : \"inactive\"}\n        data-layout={layout}\n        className={horizontalAccordionItemClassNames({ className })}\n      >\n        {children}\n      </div>\n    </ItemContext.Provider>\n  );\n});\n\nHorizontalAccordionItem.displayName = \"HorizontalAccordionItem\";\n\nexport const HorizontalAccordionBlade = forwardRef<\n  HTMLButtonElement,\n  HorizontalAccordionBladeProps\n>(\n  (\n    {\n      className,\n      children,\n      disabled = false,\n      iconPosition = \"start\",\n      onClick,\n      onFocus,\n      onKeyDown,\n      type = \"button\",\n      ...props\n    },\n    ref,\n  ) => {\n    const {\n      activationMode,\n      layout,\n      motionConfig,\n      registerBlade,\n      setActiveValue,\n      setFocusedValue,\n      tabStopValue,\n    } = useAccordionContext(\"HorizontalAccordion.Blade\");\n    const { active, bladeId, panelId, value } = useItemContext(\n      \"HorizontalAccordion.Blade\",\n    );\n    const resolvedIconPosition =\n      iconPosition === \"top\"\n        ? \"start\"\n        : iconPosition === \"bottom\"\n          ? \"end\"\n          : iconPosition;\n    const getBladeButtons = () => {\n      const root = document\n        .getElementById(bladeId)\n        ?.closest('[data-slot=\"horizontal-accordion\"]');\n\n      return Array.from(\n        root?.querySelectorAll<HTMLButtonElement>(\n          'button[data-slot=\"horizontal-accordion-blade\"]:not(:disabled)',\n        ) ?? [],\n      );\n    };\n    const isRtl = () => {\n      const root = document\n        .getElementById(bladeId)\n        ?.closest<HTMLElement>('[data-slot=\"horizontal-accordion\"]');\n      const closestDirection =\n        root?.getAttribute(\"dir\") ??\n        root?.closest<HTMLElement>(\"[dir]\")?.getAttribute(\"dir\");\n\n      return (\n        closestDirection === \"rtl\" ||\n        (root ? window.getComputedStyle(root).direction === \"rtl\" : false)\n      );\n    };\n    const focusBladeAtOffset = (offset: number) => {\n      const blades = getBladeButtons();\n      const currentIndex = blades.findIndex((blade) => blade.id === bladeId);\n\n      if (currentIndex === -1 || blades.length === 0) {\n        return;\n      }\n\n      const nextIndex = (currentIndex + offset + blades.length) % blades.length;\n      blades[nextIndex]?.focus();\n    };\n    const focusBladeAtIndex = (index: number) => {\n      const blades = getBladeButtons();\n      const targetIndex = index < 0 ? blades.length + index : index;\n\n      blades[targetIndex]?.focus();\n    };\n\n    useEffect(\n      () => registerBlade(value, disabled),\n      [disabled, registerBlade, value],\n    );\n\n    return (\n      <button\n        {...props}\n        ref={ref}\n        id={bladeId}\n        aria-controls={panelId}\n        aria-expanded={active}\n        data-slot=\"horizontal-accordion-blade\"\n        data-state={active ? \"active\" : \"inactive\"}\n        data-layout={layout}\n        data-icon-position={resolvedIconPosition}\n        className={horizontalAccordionBladeClassNames({ className })}\n        disabled={disabled}\n        tabIndex={disabled ? undefined : value === tabStopValue ? 0 : -1}\n        type={type}\n        onClick={(event) => {\n          onClick?.(event);\n\n          if (!event.defaultPrevented) {\n            setFocusedValue(value);\n            setActiveValue(value);\n          }\n        }}\n        onFocus={(event) => {\n          onFocus?.(event);\n\n          if (!event.defaultPrevented) {\n            setFocusedValue(value);\n\n            if (activationMode === \"automatic\" && !active) {\n              setActiveValue(value);\n            }\n          }\n        }}\n        onKeyDown={(event) => {\n          onKeyDown?.(event);\n\n          if (event.defaultPrevented) {\n            return;\n          }\n\n          if (event.key === \"ArrowLeft\") {\n            event.preventDefault();\n            focusBladeAtOffset(isRtl() ? 1 : -1);\n            return;\n          }\n\n          if (event.key === \"ArrowRight\") {\n            event.preventDefault();\n            focusBladeAtOffset(isRtl() ? -1 : 1);\n            return;\n          }\n\n          if (event.key === \"Home\") {\n            event.preventDefault();\n            focusBladeAtIndex(0);\n            return;\n          }\n\n          if (event.key === \"End\") {\n            event.preventDefault();\n            focusBladeAtIndex(-1);\n            return;\n          }\n\n          // Native button clicks handle Enter and Space (on key release).\n        }}\n      >\n        {active ? (\n          <motion.span\n            aria-hidden=\"true\"\n            data-slot=\"horizontal-accordion-blade-active-layer\"\n            className={horizontalAccordionBladeActiveLayerClasses}\n            layoutId=\"horizontal-accordion-active-blade\"\n            transition={motionConfig.activeLayerTransition}\n          />\n        ) : null}\n        {renderBladeChildren(children)}\n      </button>\n    );\n  },\n);\n\nHorizontalAccordionBlade.displayName = \"HorizontalAccordionBlade\";\n\nexport const HorizontalAccordionBladeIcon = forwardRef<\n  HTMLSpanElement,\n  HorizontalAccordionBladeIconProps\n>(({ className, ...props }, ref) => {\n  const { layout } = useAccordionContext(\"HorizontalAccordion.BladeIcon\");\n  const { active } = useItemContext(\"HorizontalAccordion.BladeIcon\");\n\n  return (\n    <span\n      {...props}\n      ref={ref}\n      data-slot=\"horizontal-accordion-blade-icon\"\n      data-state={active ? \"active\" : \"inactive\"}\n      data-layout={layout}\n      className={horizontalAccordionBladeIconClassNames({ className })}\n    />\n  );\n});\n\nHorizontalAccordionBladeIcon.displayName = \"HorizontalAccordionBladeIcon\";\n\nexport const HorizontalAccordionBladeLabel = forwardRef<\n  HTMLSpanElement,\n  HorizontalAccordionBladeLabelProps\n>(\n  (\n    {\n      className,\n      orientation = \"rotated\",\n      direction = \"bottom-to-top\",\n      ...props\n    },\n    ref,\n  ) => {\n    const { layout } = useAccordionContext(\"HorizontalAccordion.BladeLabel\");\n    const { active } = useItemContext(\"HorizontalAccordion.BladeLabel\");\n\n    return (\n      <span\n        {...props}\n        ref={ref}\n        data-slot=\"horizontal-accordion-blade-label\"\n        data-state={active ? \"active\" : \"inactive\"}\n        data-layout={layout}\n        data-orientation={orientation}\n        data-direction={direction}\n        className={horizontalAccordionBladeLabelClassNames({ className })}\n      />\n    );\n  },\n);\n\nHorizontalAccordionBladeLabel.displayName = \"HorizontalAccordionBladeLabel\";\n\nexport const HorizontalAccordionPanel = forwardRef<\n  HTMLDivElement,\n  HorizontalAccordionPanelProps\n>(({ className, children, ...props }, ref) => {\n  const { layout, motionConfig, unmountInactivePanels } = useAccordionContext(\n    \"HorizontalAccordion.Panel\",\n  );\n  const { active, bladeId, panelId } = useItemContext(\n    \"HorizontalAccordion.Panel\",\n  );\n  const { contentEnabled, contentEnterTransition, contentExitTransition } =\n    motionConfig;\n  const [contentSettled, setContentSettled] = useState(!active);\n\n  const [previousActive, setPreviousActive] = useState(active);\n  if (previousActive !== active) {\n    setPreviousActive(active);\n    if (active) setContentSettled(false);\n  }\n\n  const hidden = contentEnabled ? !active && contentSettled : !active;\n  let content: ReactNode;\n\n  if (!contentEnabled) {\n    content = active || !unmountInactivePanels ? children : null;\n  } else if (unmountInactivePanels) {\n    content = (\n      <AnimatePresence\n        initial={false}\n        onExitComplete={() => setContentSettled(true)}\n      >\n        {active ? (\n          <motion.div\n            key=\"content\"\n            data-slot=\"horizontal-accordion-panel-content\"\n            className=\"h-full w-full\"\n            initial={{ opacity: 0, x: 12 }}\n            animate={{\n              opacity: 1,\n              x: 0,\n              transition: contentEnterTransition,\n            }}\n            exit={{\n              opacity: 0,\n              x: 12,\n              transition: contentExitTransition,\n            }}\n          >\n            {children}\n          </motion.div>\n        ) : null}\n      </AnimatePresence>\n    );\n  } else {\n    content = (\n      <motion.div\n        data-slot=\"horizontal-accordion-panel-content\"\n        className=\"h-full w-full\"\n        initial={false}\n        animate={\n          active\n            ? { opacity: 1, x: 0, transition: contentEnterTransition }\n            : { opacity: 0, x: 12, transition: contentExitTransition }\n        }\n        onAnimationComplete={() => {\n          if (!active) {\n            setContentSettled(true);\n          }\n        }}\n      >\n        {children}\n      </motion.div>\n    );\n  }\n\n  return (\n    <div\n      {...props}\n      ref={ref}\n      id={panelId}\n      role=\"region\"\n      aria-labelledby={bladeId}\n      aria-hidden={!active || undefined}\n      inert={!active ? inertAttribute : undefined}\n      data-slot=\"horizontal-accordion-panel\"\n      data-state={active ? \"active\" : \"inactive\"}\n      data-layout={layout}\n      className={horizontalAccordionPanelClassNames({ className })}\n      hidden={hidden}\n    >\n      {content}\n    </div>\n  );\n});\n\nHorizontalAccordionPanel.displayName = \"HorizontalAccordionPanel\";\n\nmarkAccordionPart(HorizontalAccordionItem, \"Item\");\nmarkAccordionPart(HorizontalAccordionBlade, \"Blade\");\nmarkAccordionPart(HorizontalAccordionPanel, \"Panel\");\n\ntype HorizontalAccordionComponent = typeof HorizontalAccordionRoot & {\n  Item: typeof HorizontalAccordionItem;\n  Blade: typeof HorizontalAccordionBlade;\n  BladeIcon: typeof HorizontalAccordionBladeIcon;\n  BladeLabel: typeof HorizontalAccordionBladeLabel;\n  Panel: typeof HorizontalAccordionPanel;\n};\n\nexport const HorizontalAccordion = Object.assign(HorizontalAccordionRoot, {\n  Item: HorizontalAccordionItem,\n  Blade: HorizontalAccordionBlade,\n  BladeIcon: HorizontalAccordionBladeIcon,\n  BladeLabel: HorizontalAccordionBladeLabel,\n  Panel: HorizontalAccordionPanel,\n}) as HorizontalAccordionComponent;\n"
    },
    {
      "path": "packages/components/src/components/horizontal-accordion/index.ts",
      "type": "registry:file",
      "target": "~/components/dethink/components/horizontal-accordion/index.ts",
      "content": "export {\n  HorizontalAccordion,\n  HorizontalAccordionBlade,\n  HorizontalAccordionBladeIcon,\n  HorizontalAccordionBladeLabel,\n  HorizontalAccordionItem,\n  HorizontalAccordionPanel,\n  horizontalAccordionBladeClassNames,\n  horizontalAccordionBladeIconClassNames,\n  horizontalAccordionBladeLabelClassNames,\n  horizontalAccordionClassNames,\n  horizontalAccordionItemClassNames,\n  horizontalAccordionPanelClassNames,\n  type HorizontalAccordionActivationMode,\n  type HorizontalAccordionAnimation,\n  type HorizontalAccordionBladeIconPosition,\n  type HorizontalAccordionBladeIconProps,\n  type HorizontalAccordionBladeLabelDirection,\n  type HorizontalAccordionBladeLabelOrientation,\n  type HorizontalAccordionBladeLabelProps,\n  type HorizontalAccordionBladeProps,\n  type HorizontalAccordionItemProps,\n  type HorizontalAccordionLayout,\n  type HorizontalAccordionPanelProps,\n  type HorizontalAccordionProps,\n  type HorizontalAccordionValue,\n} from \"./horizontal-accordion\";\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"
    }
  ]
}
