{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "accordion",
  "type": "registry:ui",
  "title": "Accordion",
  "description": "An accessible Base UI accordion with controlled and uncontrolled state, four visual variants, interruptible disclosure transitions, and reduced-motion support.",
  "files": [
    {
      "path": "registry/sonaui/accordion/accordion.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport { Accordion } from \"@base-ui/react/accordion\";\nimport { cva } from \"class-variance-authority\";\nimport { createContext, type ReactNode, useContext } from \"react\";\n\nimport { cn } from \"@/lib/sona-utils\";\nimport AnimatedPlusMinusButton from \"./animated-plus-minus-button\";\nimport styles from \"./styles.module.css\";\n\nexport type AccordionVariant = \"default\" | \"outlined\" | \"splitted\" | \"animated\";\n\nexport interface AccordionProps\n  extends Omit<Accordion.Root.Props<string>, \"className\" | \"multiple\"> {\n  /** The accordion items. */\n  children: ReactNode;\n  /** Allows multiple accordion items to be open simultaneously. @default false */\n  allowMultiple?: boolean;\n  /** Controlled values of the currently open items. */\n  value?: string[];\n  /** Values of the initially open items for uncontrolled usage. */\n  defaultValue?: string[];\n  /** Called when the set of open item values changes. */\n  onValueChange?: Accordion.Root.Props<string>[\"onValueChange\"];\n  /** Whether the entire accordion ignores interaction. @default false */\n  disabled?: boolean;\n  /** Keeps closed panels mounted in the DOM. @default false */\n  keepMounted?: boolean;\n  /** Allows browser find-in-page to reveal matching panel content. @default false */\n  hiddenUntilFound?: boolean;\n  /** Additional classes for the accordion root. */\n  className?: string;\n  /** Visual style of the accordion. @default \"default\" */\n  variant?: AccordionVariant;\n}\n\nconst accordionWrapperVariants = cva(\n  \"flex w-full flex-col items-stretch overflow-clip rounded-2xl\",\n  {\n    variants: {\n      variant: {\n        default: \"overflow-clip rounded-2xl\",\n        outlined: \"overflow-clip rounded-2xl\",\n        splitted: \"overflow-clip rounded-2xl\",\n        animated: styles.wrapper,\n      },\n    },\n    defaultVariants: { variant: \"default\" },\n  },\n);\n\nconst accordionItemVariants = cva(\n  \"relative w-full min-w-0 overflow-hidden bg-background text-foreground transition-[transform,border-radius] duration-300\",\n  {\n    variants: {\n      variant: {\n        default: \"border-b border-border\",\n        outlined:\n          \"border-foreground border-t border-x last:border-b first:rounded-t-2xl last:rounded-b-2xl\",\n        splitted: \"rounded-2xl\",\n        animated: styles.animated,\n      },\n    },\n    defaultVariants: { variant: \"default\" },\n  },\n);\n\nconst AccordionContext = createContext<{ variant: AccordionVariant } | null>(\n  null,\n);\n\nfunction useAccordionContext(component: string) {\n  const context = useContext(AccordionContext);\n  if (!context) {\n    throw new Error(`${component} must be used within AccordionRoot`);\n  }\n  return context;\n}\n\nexport function AccordionRoot({\n  children,\n  allowMultiple = false,\n  className,\n  variant = \"default\",\n  ...props\n}: AccordionProps) {\n  return (\n    <AccordionContext.Provider value={{ variant }}>\n      <Accordion.Root\n        multiple={allowMultiple}\n        className={cn(\n          accordionWrapperVariants({ variant }),\n          variant === \"splitted\" && \"gap-y-2\",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n      </Accordion.Root>\n    </AccordionContext.Provider>\n  );\n}\n\nexport interface AccordionItemProps\n  extends Omit<Accordion.Item.Props, \"className\"> {\n  /** Stable value used to identify the item. */\n  value?: string;\n  /** Additional classes for the accordion item. */\n  className?: string;\n}\n\nexport function AccordionItem({\n  children,\n  className,\n  value,\n  ...props\n}: AccordionItemProps) {\n  const { variant } = useAccordionContext(\"AccordionItem\");\n\n  return (\n    <Accordion.Item\n      value={value}\n      className={cn(accordionItemVariants({ variant }), className)}\n      {...props}\n    >\n      <div className=\"relative w-full min-w-0\">{children}</div>\n    </Accordion.Item>\n  );\n}\n\nexport interface AccordionItemHeaderProps {\n  /** Header content displayed before the open-state icon. */\n  children: ReactNode;\n  /** Legacy item value; state is now owned by AccordionItem. */\n  value?: string;\n  /** Additional classes for the header layout. */\n  className?: string;\n}\n\nexport function AccordionItemHeader({\n  children,\n  className,\n}: AccordionItemHeaderProps) {\n  useAccordionContext(\"AccordionItemHeader\");\n  return (\n    <div\n      className={cn(\n        \"flex w-full min-w-0 items-center justify-between rounded-xl px-8 py-4 font-medium text-balance\",\n        className,\n      )}\n    >\n      <div className=\"min-w-0 flex-1\">{children}</div>\n      <AnimatedPlusMinusButton />\n    </div>\n  );\n}\n\nexport interface AccordionItemTriggerProps\n  extends Omit<Accordion.Trigger.Props, \"className\"> {\n  /** Trigger contents. */\n  children: ReactNode;\n  /** Legacy item value; state is now owned by AccordionItem. */\n  value?: string;\n  /** Additional classes for the trigger. */\n  className?: string;\n}\n\nexport function AccordionItemTrigger({\n  children,\n  className,\n  value: _value,\n  ...props\n}: AccordionItemTriggerProps) {\n  useAccordionContext(\"AccordionItemTrigger\");\n  return (\n    <Accordion.Header className=\"w-full\">\n      <Accordion.Trigger\n        className={cn(\n          \"group block w-full min-w-0 cursor-pointer text-left\",\n          \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset\",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n      </Accordion.Trigger>\n    </Accordion.Header>\n  );\n}\n\nexport interface AccordionItemContentProps\n  extends Omit<Accordion.Panel.Props, \"className\"> {\n  /** Panel contents. */\n  children: ReactNode;\n  /** Legacy item value; state is now owned by AccordionItem. */\n  value?: string;\n  /** Additional classes for the panel content. */\n  className?: string;\n}\n\nexport function AccordionItemContent({\n  children,\n  className,\n  value: _value,\n  ...props\n}: AccordionItemContentProps) {\n  useAccordionContext(\"AccordionItemContent\");\n  return (\n    <Accordion.Panel\n      className={cn(\n        \"h-[var(--accordion-panel-height)] w-full min-w-0 overflow-hidden text-sm opacity-100\",\n        \"transition-[height,opacity] duration-200 ease-[cubic-bezier(0.23,1,0.32,1)]\",\n        \"data-starting-style:h-0 data-ending-style:h-0\",\n        \"data-starting-style:opacity-0 data-ending-style:opacity-0\",\n        \"motion-reduce:transition-none\",\n      )}\n      {...props}\n    >\n      <div className={cn(\"w-full min-w-0 px-8 pb-4\", className)}>\n        {children}\n      </div>\n    </Accordion.Panel>\n  );\n}\n\nexport { AccordionContext };\n",
      "target": "components/ui/accordion/accordion.tsx"
    },
    {
      "path": "registry/sonaui/accordion/animated-plus-minus-button.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nexport interface AnimatedPlusMinusButtonProps {\n  /** Icon size in pixels. @default 24 */\n  size?: number;\n}\n\nexport default function AnimatedPlusMinusButton({\n  size = 24,\n}: AnimatedPlusMinusButtonProps) {\n  return (\n    <span aria-hidden=\"true\" className=\"flex items-center justify-center\">\n      <svg width={size} height={size} viewBox=\"0 0 24 24\">\n        <title>Expand or collapse</title>\n        <line\n          x1=\"1\"\n          y1=\"12\"\n          x2=\"23\"\n          y2=\"12\"\n          stroke=\"currentColor\"\n          strokeWidth=\"1\"\n          className=\"origin-center transition-opacity duration-200 group-data-panel-open:opacity-0 motion-reduce:transition-none\"\n        />\n        <line\n          x1=\"12\"\n          y1=\"1\"\n          x2=\"12\"\n          y2=\"23\"\n          stroke=\"currentColor\"\n          strokeWidth=\"1\"\n          className=\"origin-center transition-transform duration-200 group-data-panel-open:rotate-90 motion-reduce:transition-none\"\n        />\n      </svg>\n    </span>\n  );\n}\n",
      "target": "components/ui/accordion/animated-plus-minus-button.tsx"
    },
    {
      "path": "registry/sonaui/accordion/styles.module.css",
      "type": "registry:file",
      "target": "components/ui/accordion/styles.module.css",
      "content": ".wrapper {\n  border-radius: 1rem;\n  overflow: visible;\n}\n\n.animated {\n  --_margin-gap: 1.5rem;\n  --ease: linear(\n    0 0%,\n    0.2688 9.91%,\n    0.3859 15%,\n    0.4917 20.19%,\n    0.5865 25.5%,\n    0.6705 30.93%,\n    0.7441 36.51%,\n    0.8075 42.26%,\n    0.8593 47.98%,\n    0.9022 53.93%,\n    0.9366 60.13%,\n    0.963 66.67%,\n    0.9812 73.4%,\n    0.9929 80.76%,\n    0.9986 88.89%,\n    1 100%\n  );\n  --bounce-duration: calc((1 / var(--speed, 1)) * 1s);\n  --duration: calc((0.36 / var(--speed, 1)) * 1s);\n\n  outline: 1px solid;\n\n  transition-property: transform, border-radius;\n  transition-duration: var(--duration);\n  transition-timing-function: var(--ease);\n  transform-style: preserve-3d;\n  perspective: 120px;\n}\n\n.animated:has(~ .animated[data-open]) {\n  transform: translate3d(0, calc(var(--_margin-gap) * -1), 0);\n}\n\n.animated[data-open] ~ .animated {\n  transform: translate3d(0, calc(var(--_margin-gap) * 1), 0);\n}\n\n.animated:is(:first-child) {\n  border-top-left-radius: 1rem;\n  border-top-right-radius: 1rem;\n}\n\n.animated:is(:last-child) {\n  border-bottom-left-radius: 1rem;\n  border-bottom-right-radius: 1rem;\n}\n\n.animated[data-open] {\n  border-radius: 1rem;\n}\n\n.animated[data-open] + .animated {\n  border-top-left-radius: 1rem;\n  border-top-right-radius: 1rem;\n}\n\n.animated.animated:has(+ .animated[data-open]) {\n  border-bottom-left-radius: 1rem;\n  border-bottom-right-radius: 1rem;\n}\n"
    }
  ],
  "dependencies": [
    "@base-ui/react",
    "class-variance-authority"
  ],
  "registryDependencies": [
    "@sona-ui/sona-utils"
  ]
}