{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "flow",
  "title": "Flow",
  "description": "A process drawn from data with no diagram library: a step-by-step walkthrough, boxes and arrows that wrap, a numbered rail or one inline line.",
  "dependencies": [
    "lucide-react",
    "motion",
    "radix-ui"
  ],
  "registryDependencies": [
    "utils",
    "https://miseui.junsu4621.workers.dev/r/motion.json"
  ],
  "files": [
    {
      "path": "registry/miseui/ui/flow.tsx",
      "content": "import type * as React from \"react\"\nimport { Fragment, useId, useState } from \"react\"\nimport { Tabs as TabsPrimitive } from \"radix-ui\"\nimport { LayoutGroup, motion, useReducedMotion } from \"motion/react\"\nimport { ArrowRight } from \"lucide-react\"\nimport { SPRING_DEFAULT } from \"@/registry/miseui/lib/motion\"\nimport { FlowChain, FlowInline, FlowRail, type FlowStep } from \"@/registry/miseui/ui/flow-parts\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\ntype FlowVariant = \"walkthrough\" | \"chain\" | \"rail\" | \"inline\"\ntype FlowEffect = \"spring\" | \"sequence\"\n\ntype RootAttributes = Omit<React.ComponentProps<\"figure\">, \"children\">\n\ninterface FlowProps extends RootAttributes {\n  /** Names the steps for assistive tech. */\n  label: string\n  steps: readonly FlowStep[]\n  /** `walkthrough` one step at a time, `chain` boxes and arrows that wrap, `rail` a numbered column, `inline` a line for inside a sentence or a cell. */\n  variant?: FlowVariant\n  /** `spring` slides the walkthrough's marker between steps; `sequence` brings the other variants in, in order, the first time they are seen. */\n  effect?: FlowEffect\n  /** The step a walkthrough is on. */\n  active?: number\n  defaultActive?: number\n  onActiveChange?: (index: number) => void\n  caption?: React.ReactNode\n}\n\nconst TAB_CLASS = [\n  \"relative inline-flex min-h-10 min-w-0 items-center gap-2 rounded-full px-3 py-1 text-start text-sm text-muted-foreground outline-none\",\n  \"transition-colors duration-(--duration-fast) ease-(--ease-mise) hover:text-foreground\",\n  \"focus-visible:ring-[3px] focus-visible:ring-ring/50 data-[state=active]:text-foreground\",\n]\n\ninterface WalkthroughProps {\n  label: string\n  steps: readonly FlowStep[]\n  spring: boolean\n  active: number\n  onChange: (index: number) => void\n}\n\nfunction FlowPanel({ step, selected, spring }: { step: FlowStep; selected: boolean; spring: boolean }) {\n  return (\n    <motion.div className=\"grid min-w-0 gap-1\" initial={false} animate={{ opacity: selected ? 1 : 0 }} transition={spring ? SPRING_DEFAULT : { duration: 0 }}>\n      {step.tag ? <p className=\"text-[13px] text-muted-foreground\">{step.tag}</p> : null}\n      {step.detail ? <div className=\"text-sm leading-relaxed\">{step.detail}</div> : null}\n      {step.arrow ? (\n        <p className=\"flex items-center gap-1 pt-1 text-[13px] text-muted-foreground\">\n          <ArrowRight aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n          {step.arrow}\n        </p>\n      ) : null}\n    </motion.div>\n  )\n}\n\nfunction FlowWalkthrough({ label, steps, spring, active, onChange }: WalkthroughProps) {\n  const groupId = useId()\n  return (\n    <LayoutGroup id={groupId}>\n      <TabsPrimitive.Root value={String(active)} onValueChange={(next) => onChange(Number(next))} className=\"grid min-w-0 gap-4\">\n        <TabsPrimitive.List aria-label={label} className=\"flex min-w-0 flex-wrap items-center gap-x-1 gap-y-2\">\n          {steps.map((step, index) => (\n            <Fragment key={step.title}>\n              <TabsPrimitive.Trigger value={String(index)} className={cn(TAB_CLASS, !spring && \"data-[state=active]:bg-muted\")}>\n                {spring && index === active ? (\n                  <motion.span layoutId=\"flow-marker\" data-slot=\"flow-marker\" className=\"absolute inset-0 rounded-full bg-muted\" transition={SPRING_DEFAULT} />\n                ) : null}\n                <span aria-hidden=\"true\" className=\"relative text-[13px] tabular-nums\">{index + 1}</span>\n                <span className=\"relative min-w-0\">{step.title}</span>\n              </TabsPrimitive.Trigger>\n              {index < steps.length - 1 ? <span aria-hidden=\"true\" data-slot=\"flow-arrow\" className=\"h-px w-3 shrink-0 bg-border @max-sm:hidden\" /> : null}\n            </Fragment>\n          ))}\n        </TabsPrimitive.List>\n        {/* Every panel keeps its place in one grid cell, so the frame takes the tallest and the page does not jump between steps. */}\n        <div className=\"grid min-w-0 grid-cols-[minmax(0,1fr)] [&>*]:[grid-area:1/1]\">\n          {steps.map((step, index) => (\n            <TabsPrimitive.Content\n              key={step.title}\n              value={String(index)}\n              forceMount\n              tabIndex={index === active ? 0 : -1}\n              className=\"min-w-0 rounded-sm outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 data-[state=inactive]:invisible\"\n            >\n              <FlowPanel step={step} selected={index === active} spring={spring} />\n            </TabsPrimitive.Content>\n          ))}\n        </div>\n      </TabsPrimitive.Root>\n    </LayoutGroup>\n  )\n}\n\nconst LISTS = { chain: FlowChain, rail: FlowRail, inline: FlowInline } as const\n\nfunction Flow({\n  label, steps, variant = \"walkthrough\", effect, active, defaultActive = 0, onActiveChange, caption, className, ...props\n}: FlowProps) {\n  const reduceMotion = useReducedMotion() ?? false\n  const [uncontrolled, setUncontrolled] = useState(defaultActive)\n  const current = Math.min(Math.max(active ?? uncontrolled, 0), Math.max(steps.length - 1, 0))\n  const onChange = (next: number) => {\n    setUncontrolled(next)\n    onActiveChange?.(next)\n  }\n  let body: React.ReactNode\n  if (variant === \"walkthrough\") {\n    body = <FlowWalkthrough label={label} steps={steps} spring={effect === \"spring\" && !reduceMotion} active={current} onChange={onChange} />\n  } else {\n    const List = LISTS[variant]\n    body = <List steps={steps} sequence={effect === \"sequence\"} />\n  }\n  return (\n    <figure\n      aria-label={variant === \"walkthrough\" ? undefined : label}\n      data-slot=\"flow\"\n      data-variant={variant}\n      data-effect={effect}\n      className={cn(\"@container grid w-full min-w-0 grid-cols-[minmax(0,1fr)] gap-3\", className)}\n      {...props}\n    >\n      {body}\n      {caption ? <figcaption className=\"text-[13px] text-muted-foreground\">{caption}</figcaption> : null}\n    </figure>\n  )\n}\n\nexport { Flow, type FlowProps, type FlowStep, type FlowVariant, type FlowEffect }\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/miseui/ui/flow-parts.tsx",
      "content": "import type * as React from \"react\"\nimport { motion, useReducedMotion } from \"motion/react\"\nimport { ArrowDown, ArrowRight, ChevronRight } from \"lucide-react\"\nimport { SPRING_DEFAULT } from \"@/registry/miseui/lib/motion\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\nexport interface FlowStep {\n  title: string\n  detail?: React.ReactNode\n  /** A short line above the detail, such as who does this step. */\n  tag?: string\n  /** Words on the arrow to the next step, such as \"if approved\". */\n  arrow?: string\n}\n\nexport interface FlowListProps {\n  steps: readonly FlowStep[]\n  sequence: boolean\n}\n\nconst STAGGER_S = 0.06\nconst RISE_PX = 8\n\n/** Comes in once when first seen. The stagger is the order of the steps, so it says something a fade would not. */\nfunction FlowItem({ sequence, index, className, children }: { sequence: boolean; index: number; className?: string; children: React.ReactNode }) {\n  const reduceMotion = useReducedMotion() ?? false\n  if (!sequence || reduceMotion) return <li data-slot=\"flow-step\" className={className}>{children}</li>\n  return (\n    <motion.li\n      data-slot=\"flow-step\"\n      className={className}\n      initial={{ opacity: 0, y: RISE_PX }}\n      whileInView={{ opacity: 1, y: 0 }}\n      viewport={{ once: true }}\n      transition={{ ...SPRING_DEFAULT, delay: index * STAGGER_S }}\n    >\n      {children}\n    </motion.li>\n  )\n}\n\nfunction ArrowLabel({ children }: { children: React.ReactNode }) {\n  return <span data-slot=\"flow-arrow-label\" className=\"text-[13px] leading-tight text-muted-foreground\">{children}</span>\n}\n\nexport function FlowChain({ steps, sequence }: FlowListProps) {\n  return (\n    <ol data-slot=\"flow-list\" className=\"flex min-w-0 flex-col @3xl:flex-row\">\n      {steps.map((step, index) => (\n        <FlowItem key={step.title} sequence={sequence} index={index} className=\"flex min-w-0 flex-col @3xl:flex-1 @3xl:flex-row\">\n          <div className=\"grid min-w-0 content-start gap-1 rounded-lg border bg-card px-3 py-2 text-card-foreground @3xl:flex-1\">\n            {step.tag ? <p className=\"text-[13px] text-muted-foreground\">{step.tag}</p> : null}\n            <p className=\"text-sm font-medium\">{step.title}</p>\n            {step.detail ? <div className=\"text-[13px] leading-snug text-muted-foreground\">{step.detail}</div> : null}\n          </div>\n          {index < steps.length - 1 ? (\n            <span data-slot=\"flow-arrow\" className=\"flex shrink-0 items-center gap-2 py-2 ps-3 text-muted-foreground @3xl:flex-col @3xl:justify-center @3xl:gap-1 @3xl:px-2 @3xl:py-0\">\n              <ArrowDown aria-hidden=\"true\" className=\"size-4 @3xl:hidden\" />\n              <ArrowRight aria-hidden=\"true\" className=\"hidden size-4 @3xl:block\" />\n              {/* Narrow on a row, so the words on an arrow do not take the width from the step they connect. */}\n              {step.arrow ? <span className=\"@3xl:w-16 @3xl:text-center\"><ArrowLabel>{step.arrow}</ArrowLabel></span> : null}\n            </span>\n          ) : null}\n        </FlowItem>\n      ))}\n    </ol>\n  )\n}\n\nexport function FlowRail({ steps, sequence }: FlowListProps) {\n  return (\n    <ol data-slot=\"flow-list\" className=\"grid min-w-0\">\n      {steps.map((step, index) => {\n        const last = index === steps.length - 1\n        return (\n          <FlowItem key={step.title} sequence={sequence} index={index} className=\"grid min-w-0 grid-cols-[auto_minmax(0,1fr)] gap-x-3\">\n            <div className=\"flex flex-col items-center\">\n              <span aria-hidden=\"true\" className=\"grid size-6 shrink-0 place-items-center rounded-full border bg-background text-[13px] tabular-nums\">\n                {index + 1}\n              </span>\n              {last ? null : <span aria-hidden=\"true\" data-slot=\"flow-arrow\" className=\"w-px flex-1 bg-border\" />}\n            </div>\n            <div className={cn(\"grid min-w-0 content-start gap-1\", !last && \"pb-6\")}>\n              <p className=\"text-sm leading-6 font-medium\">{step.title}</p>\n              {step.tag ? <p className=\"text-[13px] text-muted-foreground\">{step.tag}</p> : null}\n              {step.detail ? <div className=\"text-[13px] leading-snug text-muted-foreground\">{step.detail}</div> : null}\n              {step.arrow && !last ? (\n                <span className=\"flex items-center gap-1 pt-1 text-muted-foreground\">\n                  <ArrowDown aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n                  <ArrowLabel>{step.arrow}</ArrowLabel>\n                </span>\n              ) : null}\n            </div>\n          </FlowItem>\n        )\n      })}\n    </ol>\n  )\n}\n\nexport function FlowInline({ steps, sequence }: FlowListProps) {\n  return (\n    <ol data-slot=\"flow-list\" className=\"flex min-w-0 flex-wrap items-center gap-x-1 gap-y-1 text-[13px] text-muted-foreground\">\n      {steps.map((step, index) => {\n        const last = index === steps.length - 1\n        return (\n          <FlowItem key={step.title} sequence={sequence} index={index} className=\"flex min-w-0 items-center gap-1\">\n            <span className=\"font-medium text-foreground\">{step.title}</span>\n            {/* No room to show the detail, but a screen reader has time for it. */}\n            {step.detail ? <span className=\"sr-only\">{step.detail}</span> : null}\n            {/* The condition sits before the chevron, or it reads as part of the step after it. */}\n            {step.arrow && !last ? <ArrowLabel>{step.arrow}</ArrowLabel> : null}\n            {last ? null : <ChevronRight aria-hidden=\"true\" data-slot=\"flow-arrow\" className=\"size-3.5 shrink-0\" />}\n          </FlowItem>\n        )\n      })}\n    </ol>\n  )\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "display"
  ],
  "type": "registry:ui"
}