{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stack",
  "type": "registry:ui",
  "title": "Stack",
  "description": "One-dimensional flex layout primitive for vertical and horizontal composition with token-backed gaps, alignment, wrapping, and asChild composition.",
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://components.dethink.co.uk/r/dethink-base.json"
  ],
  "files": [
    {
      "path": "packages/components/src/components/stack/stack.tsx",
      "type": "registry:file",
      "target": "~/components/dethink/components/stack/stack.tsx",
      "content": "import {\n  Children,\n  cloneElement,\n  createElement,\n  forwardRef,\n  isValidElement,\n  type ForwardedRef,\n  type FieldsetHTMLAttributes,\n  type FormHTMLAttributes,\n  type HTMLAttributes,\n  type ReactElement,\n  type ReactNode,\n  type Ref,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nexport type StackElement =\n  | \"div\"\n  | \"section\"\n  | \"article\"\n  | \"main\"\n  | \"aside\"\n  | \"nav\"\n  | \"header\"\n  | \"footer\"\n  | \"ul\"\n  | \"ol\"\n  | \"li\"\n  | \"form\"\n  | \"fieldset\"\n  | \"span\";\n\nexport type StackDirection = \"vertical\" | \"horizontal\";\nexport type StackGap =\n  \"none\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"8\" | \"10\" | \"12\";\nexport type StackAlign = \"stretch\" | \"start\" | \"center\" | \"end\" | \"baseline\";\nexport type StackJustify = \"start\" | \"center\" | \"end\" | \"between\";\nexport type StackWrap = \"nowrap\" | \"wrap\";\n\ntype StackBaseProps = {\n  align?: StackAlign;\n  as?: StackElement;\n  asChild?: boolean;\n  direction?: StackDirection;\n  gap?: StackGap;\n  justify?: StackJustify;\n  wrap?: StackWrap;\n};\n\ntype StackFormAttributes = Pick<\n  FormHTMLAttributes<HTMLFormElement>,\n  | \"acceptCharset\"\n  | \"action\"\n  | \"autoComplete\"\n  | \"encType\"\n  | \"method\"\n  | \"name\"\n  | \"noValidate\"\n  | \"target\"\n>;\n\ntype StackFieldsetAttributes = Pick<\n  FieldsetHTMLAttributes<HTMLFieldSetElement>,\n  \"disabled\" | \"form\" | \"name\"\n>;\n\ntype NativeStackProps = HTMLAttributes<HTMLElement> &\n  StackFormAttributes &\n  StackFieldsetAttributes &\n  StackBaseProps & {\n    asChild?: false;\n    children?: ReactNode;\n  };\n\ntype ChildStackProps = Omit<HTMLAttributes<HTMLElement>, \"children\"> &\n  StackBaseProps & {\n    asChild: true;\n    children: ReactElement<StackSlotProps>;\n  };\n\nexport type StackProps = NativeStackProps | ChildStackProps;\n\ntype StackSlotProps = Record<string, unknown> & {\n  children?: ReactNode;\n  className?: string;\n  ref?: Ref<HTMLElement>;\n};\n\ntype EventHandler = (...args: unknown[]) => void;\n\nconst stackBaseClasses = \"box-border flex min-w-0\";\n\nconst stackDirectionClasses: Record<StackDirection, string> = {\n  vertical: \"flex-col\",\n  horizontal: \"flex-row\",\n};\n\nconst stackGapClasses: Record<StackGap, string> = {\n  none: \"gap-[var(--dt-space-0)]\",\n  1: \"gap-[var(--dt-space-1)]\",\n  2: \"gap-[var(--dt-space-2)]\",\n  3: \"gap-[var(--dt-space-3)]\",\n  4: \"gap-[var(--dt-space-4)]\",\n  5: \"gap-[var(--dt-space-5)]\",\n  6: \"gap-[var(--dt-space-6)]\",\n  8: \"gap-[var(--dt-space-8)]\",\n  10: \"gap-[var(--dt-space-10)]\",\n  12: \"gap-[var(--dt-space-12)]\",\n};\n\nconst stackAlignClasses: Record<StackAlign, string> = {\n  stretch: \"items-stretch\",\n  start: \"items-start\",\n  center: \"items-center\",\n  end: \"items-end\",\n  baseline: \"items-baseline\",\n};\n\nconst stackJustifyClasses: Record<StackJustify, string> = {\n  start: \"justify-start\",\n  center: \"justify-center\",\n  end: \"justify-end\",\n  between: \"justify-between\",\n};\n\nconst stackWrapClasses: Record<StackWrap, string> = {\n  nowrap: \"flex-nowrap\",\n  wrap: \"flex-wrap\",\n};\n\nexport function stackClassNames({\n  align = \"stretch\",\n  className,\n  direction = \"vertical\",\n  gap = \"4\",\n  justify = \"start\",\n  wrap = \"nowrap\",\n}: Pick<\n  StackProps,\n  \"align\" | \"className\" | \"direction\" | \"gap\" | \"justify\" | \"wrap\"\n> = {}) {\n  return cn(\n    stackBaseClasses,\n    stackDirectionClasses[direction],\n    stackGapClasses[gap],\n    stackAlignClasses[align],\n    stackJustifyClasses[justify],\n    stackWrapClasses[wrap],\n    className,\n  );\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 getChildRef(child: ReactElement<StackSlotProps>) {\n  return child.props.ref;\n}\n\nfunction isEventHandler(key: string, value: unknown): value is EventHandler {\n  return /^on[A-Z]/.test(key) && typeof value === \"function\";\n}\n\nfunction isDefaultPreventedEvent(\n  event: unknown,\n): event is { defaultPrevented: boolean } {\n  return (\n    typeof event === \"object\" &&\n    event !== null &&\n    \"defaultPrevented\" in event &&\n    event.defaultPrevented === true\n  );\n}\n\nfunction composeEventHandlers(\n  componentHandler: EventHandler,\n  childHandler: EventHandler,\n): EventHandler {\n  return (...args) => {\n    componentHandler(...args);\n\n    if (!isDefaultPreventedEvent(args[0])) {\n      childHandler(...args);\n    }\n  };\n}\n\nfunction composeSlotProps(\n  componentProps: Record<string, unknown>,\n  childProps: StackSlotProps,\n) {\n  const composedProps: StackSlotProps = {\n    ...componentProps,\n    ...childProps,\n  };\n\n  for (const [key, componentValue] of Object.entries(componentProps)) {\n    const childValue = childProps[key];\n\n    if (\n      isEventHandler(key, componentValue) &&\n      isEventHandler(key, childValue)\n    ) {\n      composedProps[key] = composeEventHandlers(componentValue, childValue);\n    }\n  }\n\n  return composedProps;\n}\n\nfunction getStackDataAttributes({\n  align,\n  as,\n  asChild,\n  direction,\n  gap,\n  justify,\n  wrap,\n}: Pick<\n  StackProps,\n  \"align\" | \"as\" | \"asChild\" | \"direction\" | \"gap\" | \"justify\" | \"wrap\"\n>) {\n  return {\n    \"data-slot\": \"stack\",\n    \"data-as-child\": asChild ? \"true\" : undefined,\n    \"data-element\": asChild ? undefined : as,\n    \"data-direction\": direction,\n    \"data-gap\": gap,\n    \"data-align\": align,\n    \"data-justify\": justify,\n    \"data-wrap\": wrap,\n  };\n}\n\nexport const Stack = forwardRef<HTMLElement, StackProps>(\n  (\n    {\n      align = \"stretch\",\n      as = \"div\",\n      asChild = false,\n      children,\n      className,\n      direction = \"vertical\",\n      gap = \"4\",\n      justify = \"start\",\n      wrap = \"nowrap\",\n      ...props\n    },\n    ref,\n  ) => {\n    const classes = stackClassNames({\n      align,\n      className,\n      direction,\n      gap,\n      justify,\n      wrap,\n    });\n    const dataAttributes = getStackDataAttributes({\n      align,\n      as,\n      asChild,\n      direction,\n      gap,\n      justify,\n      wrap,\n    });\n\n    if (asChild) {\n      const child = Children.only(children);\n\n      if (!isValidElement<StackSlotProps>(child)) {\n        throw new Error(\n          \"Stack with asChild expects a single React element child.\",\n        );\n      }\n\n      const childRef = getChildRef(child);\n      const composedProps = composeSlotProps(props, child.props);\n\n      return cloneElement(child, {\n        ...composedProps,\n        ...dataAttributes,\n        ref: composeRefs(ref as Ref<HTMLElement>, childRef),\n        className: cn(classes, child.props.className),\n      });\n    }\n\n    return createElement(\n      as,\n      {\n        ...props,\n        ...dataAttributes,\n        ref: ref as ForwardedRef<HTMLElement>,\n        className: classes,\n      },\n      children,\n    );\n  },\n);\n\nStack.displayName = \"Stack\";\n"
    },
    {
      "path": "packages/components/src/components/stack/index.ts",
      "type": "registry:file",
      "target": "~/components/dethink/components/stack/index.ts",
      "content": "export {\n  Stack,\n  stackClassNames,\n  type StackAlign,\n  type StackDirection,\n  type StackElement,\n  type StackGap,\n  type StackJustify,\n  type StackProps,\n  type StackWrap,\n} from \"./stack\";\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"
    }
  ]
}
