{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stagger-list",
  "title": "Stagger List",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A list or grid whose items arrive one after another from any direction, then glide to their new places when filtered, sorted, added or removed.",
  "dependencies": [
    "motion@^12"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/stagger-list.tsx",
      "content": "// Ballmac UI: Stagger List. https://ui.ballmac.com/components/stagger-list\n\"use client\"\n\nimport * as React from \"react\"\nimport { AnimatePresence, motion, useInView, useReducedMotion, type Variants } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype StaggerDirection = \"up\" | \"down\" | \"left\" | \"right\" | \"scale\"\n\nfunction itemVariants(direction: StaggerDirection, distance: number): Variants {\n  const from: Record<StaggerDirection, Record<string, number>> = {\n    up: { y: distance },\n    down: { y: -distance },\n    left: { x: distance },\n    right: { x: -distance },\n    scale: { scale: 0.85 },\n  }\n  return {\n    hidden: { opacity: 0, ...from[direction] },\n    visible: { opacity: 1, x: 0, y: 0, scale: 1, transition: { type: \"spring\", stiffness: 260, damping: 26 } },\n  }\n}\n\nconst Context = React.createContext<{ variants: Variants; reorder: boolean }>({ variants: itemVariants(\"up\", 16), reorder: false })\n\ntype StaggerListProps = Omit<React.ComponentProps<\"ul\">, \"ref\"> & {\n  /** Element for the list. */\n  as?: \"ul\" | \"ol\" | \"div\"\n  /** Seconds between items. */\n  stagger?: number\n  /** Seconds before the first item. */\n  delay?: number\n  /** Where items come from. */\n  direction?: StaggerDirection\n  /** Travel distance in pixels. */\n  distance?: number\n  /** Wait for the list to scroll into view. */\n  inView?: boolean\n  /** Items glide to their new place when the list is filtered, sorted or items are added or removed. */\n  reorder?: boolean\n}\n\nfunction StaggerList({ as = \"ul\", stagger = 0.07, delay = 0, direction = \"up\", distance = 16, inView = true, reorder = true, className, children, ...props }: StaggerListProps) {\n  const ref = React.useRef<HTMLElement>(null)\n  const reduce = useReducedMotion()\n  const seen = useInView(ref, { once: true, margin: \"0px 0px -10% 0px\" })\n  const show = reduce || !inView || seen\n  const variants = React.useMemo(() => itemVariants(direction, distance), [direction, distance])\n  const Tag = motion[as] as typeof motion.ul\n\n  return (\n    <Context.Provider value={{ variants, reorder }}>\n      <Tag\n        ref={ref as React.Ref<HTMLUListElement>}\n        data-slot=\"stagger-list\"\n        initial={false}\n        animate={show ? \"visible\" : \"hidden\"}\n        variants={{ hidden: {}, visible: { transition: { staggerChildren: reduce ? 0 : stagger, delayChildren: reduce ? 0 : delay } } }}\n        className={className}\n        {...(props as object)}\n      >\n        <AnimatePresence initial={false} mode=\"popLayout\">\n          {children}\n        </AnimatePresence>\n      </Tag>\n    </Context.Provider>\n  )\n}\n\ntype StaggerItemProps = Omit<React.ComponentProps<\"li\">, \"ref\">\n\nfunction StaggerItem({ className, children, ...props }: StaggerItemProps) {\n  const { variants, reorder } = React.useContext(Context)\n  const reduce = useReducedMotion()\n  return (\n    <motion.li\n      data-slot=\"stagger-item\"\n      variants={reduce ? { hidden: { opacity: 1 }, visible: { opacity: 1 } } : variants}\n      layout={reorder && !reduce ? \"position\" : false}\n      exit={reduce ? undefined : { opacity: 0, scale: 0.9, transition: { duration: 0.15 } }}\n      className={cn(className)}\n      {...(props as object)}\n    >\n      {children}\n    </motion.li>\n  )\n}\n\nexport { StaggerList, StaggerItem, type StaggerListProps, type StaggerItemProps }\n",
      "type": "registry:ui",
      "target": "@components/ballmac/stagger-list.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "list",
      "stagger",
      "reorder",
      "filter",
      "entrance"
    ],
    "version": "1.0.0",
    "updated": "2026-10-01",
    "ai": {
      "summary": "<StaggerList stagger direction distance inView reorder><StaggerItem key={id}>…</StaggerItem></StaggerList>. Keep each item's key stable and filtering or sorting animates automatically.",
      "whenToUse": [
        "Result lists that filter or sort",
        "Feature grids that should arrive in sequence"
      ],
      "whenNotToUse": [
        "A live feed where new items push others down (animated-list)",
        "Plain fade-ins (blur-fade)"
      ],
      "composesWith": [
        "animated-list",
        "blur-fade",
        "bento-grid"
      ],
      "a11y": [
        {
          "keys": "Screen readers",
          "action": "The real list markup is untouched; only opacity and position change"
        },
        {
          "keys": "Reduced motion",
          "action": "Items are shown at once and reordering is instant"
        }
      ],
      "customization": [
        "as: ul | ol | div",
        "stagger and delay",
        "direction: up | down | left | right | scale",
        "reorder"
      ]
    },
    "examples": [
      "stagger-list-demo",
      "stagger-list-directions"
    ],
    "url": "https://ui.ballmac.com/components/stagger-list"
  },
  "categories": [
    "motion"
  ],
  "type": "registry:ui"
}