{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "primitives-animate-pinned-list",
  "title": "Pin List",
  "description": "A pin list component that allows you to pin items to the top of the list.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "@unlumen-ui/primitives-animate-slot"
  ],
  "files": [
    {
      "path": "registry/primitives/animate/pinned-list/index.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n  motion,\n  LayoutGroup,\n  AnimatePresence,\n  type HTMLMotionProps,\n} from \"motion/react\";\n\nimport { Slot, type WithAsChild } from \"@/components/unlumen-ui/primitives/animate/slot\";\nimport { getStrictContext } from \"@/lib/get-strict-context\";\n\ntype PinnedListContextType = {\n  movingId: string | null;\n  setMovingId: (id: string | null) => void;\n  onPinnedChange?: (id: string) => void;\n};\n\ntype PinnedListItemContextType = {\n  id: string;\n};\n\nconst [PinnedListProvider, usePinnedList] =\n  getStrictContext<PinnedListContextType>(\"PinnedListContext\");\n\nconst [PinnedListItemProvider, usePinnedListItem] =\n  getStrictContext<PinnedListItemContextType>(\"PinnedListItemContext\");\n\ntype PinnedListProps = HTMLMotionProps<\"div\"> & {\n  children: React.ReactNode;\n  onPinnedChange?: (id: string) => void;\n};\n\nfunction PinnedList({ children, onPinnedChange, ...props }: PinnedListProps) {\n  const [movingId, setMovingId] = React.useState<string | null>(null);\n\n  return (\n    <PinnedListProvider value={{ movingId, setMovingId, onPinnedChange }}>\n      <motion.div data-slot=\"pinned-list\" {...props}>\n        <LayoutGroup>{children}</LayoutGroup>\n      </motion.div>\n    </PinnedListProvider>\n  );\n}\n\ntype PinnedListPinnedProps = React.ComponentProps<\"div\"> & {\n  children: React.ReactNode;\n};\n\nfunction PinnedListPinned(props: PinnedListPinnedProps) {\n  return <div data-slot=\"pinned-list-pinned\" {...props} />;\n}\n\ntype PinnedListUnpinnedProps = React.ComponentProps<\"div\"> & {\n  children: React.ReactNode;\n};\n\nfunction PinnedListUnpinned(props: PinnedListUnpinnedProps) {\n  return <div data-slot=\"pinned-list-unpinned\" {...props} />;\n}\n\ntype PinnedListLabelProps = WithAsChild<\n  HTMLMotionProps<\"p\"> & {\n    hide?: boolean;\n  }\n>;\n\nfunction PinnedListLabel({\n  hide = false,\n  asChild = false,\n  transition = { duration: 0.22, ease: \"easeInOut\" },\n  ...props\n}: PinnedListLabelProps) {\n  const Component = asChild ? Slot : motion.p;\n\n  return (\n    <AnimatePresence initial={false}>\n      {!hide && (\n        <Component\n          layout\n          key=\"pinned-list-label\"\n          initial={{ opacity: 0 }}\n          animate={{ opacity: 1 }}\n          exit={{ opacity: 0 }}\n          transition={transition}\n          {...props}\n        />\n      )}\n    </AnimatePresence>\n  );\n}\n\ntype PinnedListItemsProps = React.ComponentProps<\"div\"> & {\n  children: React.ReactNode;\n};\n\nfunction PinnedListItems(props: PinnedListItemsProps) {\n  return <div data-slot=\"pinned-list-items\" {...props} />;\n}\n\ntype PinnedListItemProps = WithAsChild<\n  HTMLMotionProps<\"div\"> & {\n    id: string;\n    children: React.ReactNode;\n    customTrigger?: boolean;\n  }\n>;\n\nfunction PinnedListItem({\n  id,\n  asChild = false,\n  customTrigger = false,\n  transition = { stiffness: 320, damping: 25, mass: 0.8, type: \"spring\" },\n  onClick,\n  ...props\n}: PinnedListItemProps) {\n  const { movingId, setMovingId, onPinnedChange } = usePinnedList();\n\n  const Component = asChild ? Slot : motion.div;\n\n  return (\n    <PinnedListItemProvider value={{ id }}>\n      <Component\n        data-slot=\"pinned-list-item\"\n        layoutId={`pinned-list-item-${id}`}\n        style={{\n          position: \"relative\",\n          zIndex: movingId === id ? 10 : undefined,\n        }}\n        onLayoutAnimationComplete={() => {\n          if (id === movingId) setMovingId(null);\n        }}\n        onClick={(e: React.MouseEvent<HTMLDivElement>) => {\n          if (!customTrigger) {\n            setMovingId(id);\n            onPinnedChange?.(id);\n          }\n          onClick?.(e);\n        }}\n        transition={transition}\n        whileHover={!customTrigger ? { scale: 1.05 } : undefined}\n        whileTap={!customTrigger ? { scale: 0.95 } : undefined}\n        {...props}\n      />\n    </PinnedListItemProvider>\n  );\n}\n\ntype PinnedListTriggerProps = WithAsChild<HTMLMotionProps<\"button\">>;\n\nfunction PinnedListTrigger({\n  asChild = false,\n  onClick,\n  ...props\n}: PinnedListTriggerProps) {\n  const { setMovingId, onPinnedChange } = usePinnedList();\n  const { id } = usePinnedListItem();\n\n  const Component = asChild ? Slot : motion.button;\n\n  return (\n    <Component\n      data-slot=\"pinned-list-trigger\"\n      onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n        e.stopPropagation();\n        setMovingId(id);\n        onPinnedChange?.(id);\n        onClick?.(e);\n      }}\n      whileHover={{ scale: 1.05 }}\n      whileTap={{ scale: 0.95 }}\n      {...props}\n    />\n  );\n}\n\nexport {\n  PinnedList,\n  PinnedListPinned,\n  PinnedListUnpinned,\n  PinnedListLabel,\n  PinnedListItems,\n  PinnedListItem,\n  PinnedListTrigger,\n  usePinnedList,\n  usePinnedListItem,\n  type PinnedListProps,\n  type PinnedListPinnedProps,\n  type PinnedListUnpinnedProps,\n  type PinnedListLabelProps,\n  type PinnedListItemsProps,\n  type PinnedListItemProps,\n  type PinnedListTriggerProps,\n  type PinnedListContextType,\n  type PinnedListItemContextType,\n};\n",
      "type": "registry:ui",
      "target": "components/unlumen-ui/primitives/animate/pinned-list.tsx"
    }
  ],
  "type": "registry:ui"
}