{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "split-button",
  "type": "registry:ui",
  "title": "Split Button",
  "description": "Split Button joins one primary Button action with a related Menu trigger using shared outer chrome — composition only; Button and Menu keep their own APIs.",
  "author": "Skrewww",
  "dependencies": [],
  "registryDependencies": [
    "@skrewww/foundation"
  ],
  "docs": "Host requirements (assumed already present, not installed by this command): react, react-dom.",
  "files": [
    {
      "path": "components/ui/SplitButton.tsx",
      "content": "/** @skrewww-component split-button */\n\"use client\";\n\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { ButtonGroupContext } from \"@/components/ui/button-group-context\";\nimport styles from \"@/components/ui/button-group.module.css\";\n\n/**\n * Chrome divider color visible in the 2px gap between primary action and\n * menu trigger. Matches Figma Style’s gap fill (same tokens as Button Group).\n * - neutral → Secondary Style (semantic/border/default)\n * - primary → Primary Style (color/brand/700)\n * - danger → Danger Style (color/danger/700)\n */\nexport type SplitButtonDivider = \"neutral\" | \"primary\" | \"danger\";\n\nexport type SplitButtonProps = {\n  /**\n   * Composition: one primary `Button` plus a `Menu` whose `MenuTrigger`\n   * wraps a secondary `Button` (typically icon-only CaretDown with aria-label).\n   * Split Button does not own Button or Menu props.\n   */\n  children: ReactNode;\n  /**\n   * Accessible name for the related primary + menu pair.\n   * Prefer when there is no visible group label.\n   */\n  \"aria-label\"?: string;\n  \"aria-labelledby\"?: string;\n  /** Gap/chrome divider tone. Default matches Figma Secondary Style. */\n  divider?: SplitButtonDivider;\n  className?: string;\n} & Omit<HTMLAttributes<HTMLDivElement>, \"children\" | \"role\" | \"aria-label\" | \"aria-labelledby\">;\n\nconst dividerClass: Record<SplitButtonDivider, string> = {\n  neutral: styles.dividerNeutral,\n  primary: styles.dividerPrimary,\n  danger: styles.dividerDanger,\n};\n\n/**\n * Joined visual pair: one primary Button action + a related Menu trigger.\n *\n * Button remains the authority for the primary action. Menu / MenuTrigger\n * remain the authority for popup/menu behavior. This component only owns\n * adjacency chrome (shared outer border, 2px divider gap, outer corners).\n *\n * Not Button Group (peer actions), not Toggle Group, not a menu framework.\n */\nexport function SplitButton({\n  children,\n  className,\n  divider = \"neutral\",\n  \"aria-label\": ariaLabel,\n  \"aria-labelledby\": ariaLabelledBy,\n  ...rest\n}: SplitButtonProps) {\n  return (\n    <ButtonGroupContext.Provider value={true}>\n      <div\n        role=\"group\"\n        aria-label={ariaLabel}\n        aria-labelledby={ariaLabelledBy}\n        className={cn(styles.group, dividerClass[divider], className)}\n        {...rest}\n      >\n        {children}\n      </div>\n    </ButtonGroupContext.Provider>\n  );\n}\n",
      "type": "registry:ui",
      "target": "~/components/ui/SplitButton.tsx"
    },
    {
      "path": "lib/cn.ts",
      "content": "export function cn(...classes: Array<string | false | null | undefined>): string {\n  return classes.filter(Boolean).join(\" \");\n}\n",
      "type": "registry:lib",
      "target": "~/lib/cn.ts"
    },
    {
      "path": "components/ui/button-group-context.ts",
      "content": "\"use client\";\n\nimport { createContext, useContext } from \"react\";\n\n/**\n * When true, Button applies joined-item geometry for ButtonGroup /\n * SplitButton: zero individual radius (except first/last via group CSS),\n * transparent border, and no squircle clip that would fight the shared\n * outer chrome.\n */\nexport const ButtonGroupContext = createContext(false);\n\nexport function useButtonGroupItem(): boolean {\n  return useContext(ButtonGroupContext);\n}\n",
      "type": "registry:lib",
      "target": "~/components/ui/button-group-context.ts"
    },
    {
      "path": "components/ui/button-group.module.css",
      "content": ".group {\n  box-sizing: border-box;\n  display: inline-flex;\n  flex-direction: row;\n  align-items: stretch;\n  /* Figma spacing/2 — divider gap between segments */\n  gap: 0.125rem;\n  max-width: 100%;\n  border: 1px solid var(--semantic-border-default);\n  border-radius: var(--component-button-radius-control, var(--shape-radius-control));\n  background: var(--button-group-divider);\n  /* Do NOT overflow:hidden — would clip Button focus-visible rings */\n}\n\n.group > *:first-child {\n  border-start-start-radius: var(--component-button-radius-control, var(--shape-radius-control));\n  border-end-start-radius: var(--component-button-radius-control, var(--shape-radius-control));\n}\n\n.group > *:last-child {\n  border-start-end-radius: var(--component-button-radius-control, var(--shape-radius-control));\n  border-end-end-radius: var(--component-button-radius-control, var(--shape-radius-control));\n}\n\n.group > *:only-child {\n  border-radius: var(--component-button-radius-control, var(--shape-radius-control));\n}\n\n.dividerNeutral {\n  --button-group-divider: var(--semantic-border-default);\n}\n\n.dividerPrimary {\n  /* Figma Primary Style fill behind the 2px gap = color/brand/700 */\n  --button-group-divider: var(--primitive-color-brand-700);\n}\n\n.dividerDanger {\n  /* Figma Danger Style fill behind the 2px gap = color/danger/700 */\n  --button-group-divider: var(--primitive-color-danger-700);\n}\n",
      "type": "registry:ui",
      "target": "~/components/ui/button-group.module.css"
    }
  ]
}
