{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stepper-intent-onboarding",
  "title": "Stepper Intent Onboarding",
  "description": "An intent-driven onboarding block with hidden Stepper state, intent routing, profile validation, interests, async setup, and a signed-in completion state.",
  "dependencies": [
    "@radix-ui/react-slot",
    "lucide-react",
    "react-icons",
    "react-hook-form",
    "zod"
  ],
  "registryDependencies": [
    "button",
    "checkbox",
    "field",
    "input",
    "separator"
  ],
  "files": [
    {
      "path": "registry/default/ui/stepper.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\nimport { cn } from \"@/lib/utils\";\n\n// ----------------------------------------------------------------------------\n// Types\n// ----------------------------------------------------------------------------\n\ntype StepperOrientation = \"horizontal\" | \"vertical\";\ntype StepperValue = string;\ntype StepperStepPosition = \"previous\" | \"current\" | \"next\";\ntype StepperStepState =\n  | \"inactive\"\n  | \"active\"\n  | \"completed\"\n  | \"disabled\"\n  | \"error\";\n\ntype StepperStepInput<TValue extends StepperValue = StepperValue> = {\n  value: TValue;\n  disabled?: boolean;\n};\n\ntype StepperStep<TValue extends StepperValue = StepperValue> = {\n  value: TValue;\n  disabled: boolean;\n};\n\ntype StepperStepsValue<TSteps extends readonly StepperStepInput[]> =\n  TSteps[number][\"value\"];\n\ntype RegisteredStep<TValue extends StepperValue = StepperValue> =\n  StepperStep<TValue> & {\n    id: string;\n  };\n\ntype StepperNavigationGuard = () => boolean | Promise<boolean>;\n\ntype StepperApi<TValue extends StepperValue = StepperValue> = {\n  value: TValue | undefined;\n  orientation: StepperOrientation;\n  steps: StepperStep<TValue>[];\n  currentIndex: number;\n  totalSteps: number;\n  setValue: (value: TValue) => void;\n  getStepIndex: (value: TValue) => number;\n  canGoPrevious: boolean;\n  canGoNext: boolean;\n  goPrevious: () => void;\n  goNext: () => void;\n};\n\ntype StepperItemApi<TValue extends StepperValue = StepperValue> = {\n  value: TValue;\n  index: number;\n  disabled: boolean;\n  completed: boolean;\n  isActive: boolean;\n  stepState: StepperStepState;\n  stepPosition: StepperStepPosition;\n  orientation: StepperOrientation;\n  setValue: (value: TValue) => void;\n  triggerId: string;\n  contentId: string;\n};\n\ntype StepperContextValue<TValue extends StepperValue = StepperValue> =\n  StepperApi<TValue> & {\n    isExplicitMode: boolean;\n    transitionFromIndex: number;\n    transitionToIndex: number;\n    registerStep: (step: RegisteredStep) => void;\n    unregisterStep: (id: string) => void;\n    getTriggerId: (value: TValue) => string;\n    getContentId: (value: TValue) => string;\n  };\n\ntype StepperItemContextValue<TValue extends StepperValue = StepperValue> =\n  StepperItemApi<TValue>;\n\ntype StepperProps<TValue extends StepperValue = StepperValue> =\n  React.ComponentPropsWithoutRef<\"div\"> & {\n    value?: TValue;\n    defaultValue?: TValue;\n    onValueChange?: (value: TValue) => void;\n    orientation?: StepperOrientation;\n    steps?: readonly StepperStepInput<TValue>[];\n  };\n\ntype StepperPropsWithSteps<\n  TSteps extends readonly StepperStepInput[],\n> = Omit<StepperProps<StepperStepsValue<TSteps>>, \"steps\"> & {\n  steps: TSteps;\n};\n\ntype StepperPropsWithoutSteps<\n  TValue extends StepperValue = StepperValue,\n> = Omit<StepperProps<TValue>, \"steps\"> & {\n  steps?: undefined;\n};\n\ntype StepperListProps = React.ComponentPropsWithoutRef<\"ol\">;\n\ntype StepperItemProps<TValue extends StepperValue = StepperValue> = Omit<\n  React.ComponentPropsWithoutRef<\"li\">,\n  \"value\"\n> & {\n  value: TValue;\n  completed?: boolean;\n  defaultTrigger?: boolean;\n  disabled?: boolean;\n  error?: boolean;\n  separator?: boolean;\n};\n\ntype StepperTriggerProps = React.ComponentPropsWithoutRef<\"button\"> & {\n  asChild?: boolean;\n};\n\ntype StepperIndicatorProps = React.ComponentPropsWithoutRef<\"span\">;\n\ntype StepperLabelProps = React.ComponentPropsWithoutRef<\"span\">;\n\ntype StepperDescriptionProps = React.ComponentPropsWithoutRef<\"span\">;\n\ntype StepperSeparatorProps = React.ComponentPropsWithoutRef<\"span\">;\n\ntype StepperContentProps<TValue extends StepperValue = StepperValue> =\n  React.ComponentPropsWithoutRef<\"div\"> & {\n    value: TValue;\n    forceMount?: boolean;\n    keepMounted?: boolean;\n    asChild?: boolean;\n  };\n\ntype StepperButtonProps = React.ComponentPropsWithoutRef<\"button\"> & {\n  asChild?: boolean;\n};\n\ntype StepperPreviousProps = StepperButtonProps & {\n  onBeforePrevious?: StepperNavigationGuard;\n};\n\ntype StepperNextProps = StepperButtonProps & {\n  onBeforeNext?: StepperNavigationGuard;\n};\n\n// ----------------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------------\n\nconst isDevelopment = process.env.NODE_ENV !== \"production\";\n\nfunction warnDev(message: string) {\n  if (isDevelopment) {\n    console.warn(message);\n  }\n}\n\nfunction getSafeId(value: StepperValue) {\n  return value.replace(/[^a-zA-Z0-9_-]/g, \"-\");\n}\n\nfunction normalizeStep<TValue extends StepperValue>(\n  step: StepperStepInput<TValue>\n): StepperStep<TValue> {\n  return {\n    value: step.value,\n    disabled: Boolean(step.disabled),\n  };\n}\n\nfunction normalizeSteps<TValue extends StepperValue>(\n  steps: readonly StepperStepInput<TValue>[] | undefined\n) {\n  return steps?.map(normalizeStep) ?? [];\n}\n\nfunction getDuplicateStepValues<TValue extends StepperValue>(\n  steps: ReadonlyArray<{ value: TValue }>\n) {\n  const seenValues = new Set<TValue>();\n  const duplicateValues = new Set<TValue>();\n\n  steps.forEach((step) => {\n    if (seenValues.has(step.value)) {\n      duplicateValues.add(step.value);\n      return;\n    }\n\n    seenValues.add(step.value);\n  });\n\n  return Array.from(duplicateValues);\n}\n\nfunction getStepByValue<TValue extends StepperValue>(\n  steps: readonly StepperStep<TValue>[],\n  value: TValue | undefined\n) {\n  return steps.find((step) => step.value === value);\n}\n\nfunction getCurrentStepValue<TValue extends StepperValue>(\n  steps: readonly StepperStep<TValue>[],\n  selectedValue: TValue | undefined\n) {\n  const selectedStep = getStepByValue(steps, selectedValue);\n\n  if (selectedStep && !selectedStep.disabled) {\n    return selectedStep.value;\n  }\n\n  return steps.find((step) => !step.disabled)?.value;\n}\n\nfunction getNextEnabledStep<TValue extends StepperValue>(\n  steps: readonly StepperStep<TValue>[],\n  currentValue: TValue | undefined\n) {\n  const currentIndex = steps.findIndex((step) => step.value === currentValue);\n\n  if (currentIndex === -1) {\n    return undefined;\n  }\n\n  return steps.slice(currentIndex + 1).find((step) => !step.disabled);\n}\n\nfunction getPreviousEnabledStep<TValue extends StepperValue>(\n  steps: readonly StepperStep<TValue>[],\n  currentValue: TValue | undefined\n) {\n  const currentIndex = steps.findIndex((step) => step.value === currentValue);\n\n  if (currentIndex === -1) {\n    return undefined;\n  }\n\n  return steps\n    .slice(0, currentIndex)\n    .reverse()\n    .find((step) => !step.disabled);\n}\n\nfunction getKeyboardNavigationStepValue<TValue extends StepperValue>({\n  key,\n  orientation,\n  steps,\n  value,\n}: {\n  key: string;\n  orientation: StepperOrientation;\n  steps: readonly StepperStep<TValue>[];\n  value: TValue;\n}) {\n  const enabledSteps = steps.filter((step) => !step.disabled);\n  const currentIndex = enabledSteps.findIndex((step) => step.value === value);\n\n  if (currentIndex < 0) {\n    return undefined;\n  }\n\n  if (key === \"Home\") {\n    return enabledSteps.at(0)?.value;\n  }\n\n  if (key === \"End\") {\n    return enabledSteps.at(-1)?.value;\n  }\n\n  if (\n    (orientation === \"horizontal\" && key === \"ArrowRight\") ||\n    (orientation === \"vertical\" && key === \"ArrowDown\")\n  ) {\n    return enabledSteps[Math.min(currentIndex + 1, enabledSteps.length - 1)]\n      ?.value;\n  }\n\n  if (\n    (orientation === \"horizontal\" && key === \"ArrowLeft\") ||\n    (orientation === \"vertical\" && key === \"ArrowUp\")\n  ) {\n    return enabledSteps[Math.max(currentIndex - 1, 0)]?.value;\n  }\n\n  return undefined;\n}\n\nasync function resolveNavigationGuard(\n  guard: StepperNavigationGuard | undefined\n) {\n  if (!guard) {\n    return true;\n  }\n\n  return (await guard()) !== false;\n}\n\nfunction setDisplayName(component: object, displayName: string) {\n  (component as { displayName?: string }).displayName = displayName;\n}\n\n// ----------------------------------------------------------------------------\n// Context\n// ----------------------------------------------------------------------------\n\nconst StepperContext = React.createContext<StepperContextValue | null>(null);\nconst StepperItemContext =\n  React.createContext<StepperItemContextValue | null>(null);\nconst StepperListContext = React.createContext(false);\n\nfunction useStepperContext(component: string) {\n  const context = React.useContext(StepperContext);\n\n  if (!context) {\n    throw new Error(`${component} must be used within Stepper`);\n  }\n\n  return context;\n}\n\nfunction useStepperItemContext(component: string) {\n  const context = React.useContext(StepperItemContext);\n\n  if (!context) {\n    throw new Error(`${component} must be used within StepperItem`);\n  }\n\n  return context;\n}\n\nfunction useStepperListContext() {\n  return React.useContext(StepperListContext);\n}\n\n// ----------------------------------------------------------------------------\n// Internal Hooks\n// ----------------------------------------------------------------------------\n\nfunction useRegisteredSteps() {\n  const [registeredSteps, setRegisteredSteps] = React.useState<\n    RegisteredStep[]\n  >([]);\n\n  const registerStep = React.useCallback((step: RegisteredStep) => {\n    setRegisteredSteps((currentSteps) => {\n      const existingStepIndex = currentSteps.findIndex(\n        (currentStep) => currentStep.id === step.id\n      );\n\n      if (existingStepIndex === -1) {\n        return [...currentSteps, step];\n      }\n\n      const existingStep = currentSteps[existingStepIndex];\n\n      if (\n        existingStep.value === step.value &&\n        existingStep.disabled === step.disabled\n      ) {\n        return currentSteps;\n      }\n\n      const nextSteps = [...currentSteps];\n      nextSteps[existingStepIndex] = step;\n\n      return nextSteps;\n    });\n  }, []);\n\n  const unregisterStep = React.useCallback((stepId: string) => {\n    setRegisteredSteps((currentSteps) =>\n      currentSteps.filter((step) => step.id !== stepId)\n    );\n  }, []);\n\n  return {\n    registeredSteps,\n    registerStep,\n    unregisterStep,\n  };\n}\n\nfunction useStepperSteps(\n  stepsProp: readonly StepperStepInput[] | undefined,\n  registeredSteps: RegisteredStep[]\n) {\n  const isExplicitMode = stepsProp !== undefined;\n  const explicitSteps = React.useMemo(\n    () => (isExplicitMode ? normalizeSteps(stepsProp) : undefined),\n    [isExplicitMode, stepsProp]\n  );\n  const steps = React.useMemo(\n    () =>\n      explicitSteps ??\n      registeredSteps.map((step) => ({\n        value: step.value,\n        disabled: step.disabled,\n      })),\n    [explicitSteps, registeredSteps]\n  );\n\n  return {\n    isExplicitMode,\n    steps,\n  };\n}\n\nfunction useStepperValue({\n  value,\n  defaultValue,\n  onValueChange,\n  steps,\n}: {\n  value: StepperValue | undefined;\n  defaultValue: StepperValue | undefined;\n  onValueChange: ((value: StepperValue) => void) | undefined;\n  steps: StepperStep[];\n}) {\n  const isControlled = value !== undefined;\n  const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);\n  const selectedValue = isControlled ? value : uncontrolledValue;\n  const currentValue = React.useMemo(\n    () => getCurrentStepValue(steps, selectedValue),\n    [selectedValue, steps]\n  );\n  const currentIndex = React.useMemo(\n    () =>\n      currentValue === undefined\n        ? -1\n        : steps.findIndex((step) => step.value === currentValue),\n    [currentValue, steps]\n  );\n\n  const setValue = React.useCallback(\n    (nextValue: StepperValue) => {\n      const nextStepRecord = getStepByValue(steps, nextValue);\n\n      if (!nextStepRecord || nextStepRecord.disabled) {\n        return;\n      }\n\n      if (!isControlled) {\n        setUncontrolledValue(nextValue);\n      }\n\n      onValueChange?.(nextValue);\n    },\n    [isControlled, onValueChange, steps]\n  );\n\n  return {\n    currentValue,\n    currentIndex,\n    setValue,\n  };\n}\n\nfunction useStepperNavigation({\n  currentValue,\n  setValue,\n  steps,\n}: {\n  currentValue: StepperValue | undefined;\n  setValue: (value: StepperValue) => void;\n  steps: StepperStep[];\n}) {\n  const previousStep = React.useMemo(\n    () => getPreviousEnabledStep(steps, currentValue),\n    [currentValue, steps]\n  );\n  const nextStep = React.useMemo(\n    () => getNextEnabledStep(steps, currentValue),\n    [currentValue, steps]\n  );\n  const goPrevious = React.useCallback(() => {\n    if (previousStep) {\n      setValue(previousStep.value);\n    }\n  }, [previousStep, setValue]);\n  const goNext = React.useCallback(() => {\n    if (nextStep) {\n      setValue(nextStep.value);\n    }\n  }, [nextStep, setValue]);\n\n  return {\n    canGoPrevious: Boolean(previousStep),\n    canGoNext: Boolean(nextStep),\n    goPrevious,\n    goNext,\n  };\n}\n\nfunction useStepperTransition(currentIndex: number) {\n  const previousIndexRef = React.useRef(currentIndex);\n  const [transition, setTransition] = React.useState(() => ({\n    from: currentIndex,\n    to: currentIndex,\n  }));\n\n  React.useLayoutEffect(() => {\n    const previousIndex = previousIndexRef.current;\n\n    if (previousIndex === currentIndex) {\n      return;\n    }\n\n    setTransition({\n      from: previousIndex,\n      to: currentIndex,\n    });\n    previousIndexRef.current = currentIndex;\n  }, [currentIndex]);\n\n  return transition;\n}\n\nfunction getStepTransitionDelay({\n  from,\n  index,\n  to,\n}: {\n  from: number;\n  index: number;\n  to: number;\n}) {\n  if (from < 0 || to < 0 || index < 0 || from === to) {\n    return 0;\n  }\n\n  if (to > from) {\n    return index >= from && index < to ? (index - from) * 80 : 0;\n  }\n\n  return index >= to && index < from ? (from - index - 1) * 80 : 0;\n}\n\nfunction useDuplicateStepWarning(steps: StepperStep[]) {\n  const duplicateStepValues = React.useMemo(\n    () => getDuplicateStepValues(steps),\n    [steps]\n  );\n  const duplicateStepValuesKey = duplicateStepValues.join(\"\\0\");\n\n  React.useEffect(() => {\n    if (!isDevelopment || duplicateStepValues.length === 0) {\n      return;\n    }\n\n    duplicateStepValues.forEach((stepValue) => {\n      warnDev(\n        `StepperItem value \"${stepValue}\" is duplicated. Step values must be unique within a Stepper.`\n      );\n    });\n  }, [duplicateStepValues, duplicateStepValuesKey]);\n}\n\nfunction useNavigationButton({\n  canNavigate,\n  disabled,\n  navigate,\n  onBeforeNavigate,\n}: {\n  canNavigate: boolean;\n  disabled: boolean | undefined;\n  navigate: () => void;\n  onBeforeNavigate: StepperNavigationGuard | undefined;\n}) {\n  const [isPending, setIsPending] = React.useState(false);\n  const pendingRef = React.useRef(false);\n  const isDisabled = disabled || !canNavigate || isPending;\n\n  const handleClick = React.useCallback(\n    async (\n      event: React.MouseEvent<HTMLButtonElement>,\n      onClick: React.MouseEventHandler<HTMLButtonElement> | undefined\n    ) => {\n      onClick?.(event);\n\n      if (isDisabled || pendingRef.current) {\n        event.preventDefault();\n        return;\n      }\n\n      if (event.defaultPrevented) {\n        return;\n      }\n\n      pendingRef.current = true;\n      setIsPending(true);\n\n      try {\n        const canCompleteNavigation =\n          await resolveNavigationGuard(onBeforeNavigate);\n\n        if (canCompleteNavigation) {\n          navigate();\n        }\n      } finally {\n        pendingRef.current = false;\n        setIsPending(false);\n      }\n    },\n    [isDisabled, navigate, onBeforeNavigate]\n  );\n\n  return {\n    isDisabled,\n    handleClick,\n  };\n}\n\nfunction useStepper<\n  TValue extends StepperValue = StepperValue,\n>(): StepperApi<TValue> {\n  const context = useStepperContext(\n    \"useStepper\"\n  ) as unknown as StepperContextValue<TValue>;\n\n  return {\n    value: context.value,\n    orientation: context.orientation,\n    steps: context.steps,\n    currentIndex: context.currentIndex,\n    totalSteps: context.totalSteps,\n    setValue: context.setValue,\n    getStepIndex: context.getStepIndex,\n    canGoPrevious: context.canGoPrevious,\n    canGoNext: context.canGoNext,\n    goPrevious: context.goPrevious,\n    goNext: context.goNext,\n  };\n}\n\nfunction useStepperItem<\n  TValue extends StepperValue = StepperValue,\n>(): StepperItemApi<TValue> {\n  return useStepperItemContext(\n    \"useStepperItem\"\n  ) as unknown as StepperItemContextValue<TValue>;\n}\n\n// ----------------------------------------------------------------------------\n// Root\n// ----------------------------------------------------------------------------\n\nfunction Stepper<const TSteps extends readonly StepperStepInput[]>(\n  props: StepperPropsWithSteps<TSteps>\n): React.ReactElement;\nfunction Stepper<TValue extends StepperValue = StepperValue>(\n  props: StepperPropsWithoutSteps<TValue>\n): React.ReactElement;\nfunction Stepper({\n  value,\n  defaultValue,\n  onValueChange,\n  orientation = \"horizontal\",\n  steps: stepsProp,\n  className,\n  children,\n  ...props\n}: StepperProps) {\n  const id = React.useId();\n  const { registeredSteps, registerStep, unregisterStep } =\n    useRegisteredSteps();\n  const { isExplicitMode, steps } = useStepperSteps(\n    stepsProp,\n    registeredSteps\n  );\n  const {\n    currentValue,\n    currentIndex,\n    setValue: setStepperValue,\n  } = useStepperValue({\n    value,\n    defaultValue,\n    onValueChange,\n    steps,\n  });\n  const { canGoPrevious, canGoNext, goPrevious, goNext } =\n    useStepperNavigation({\n      currentValue,\n      setValue: setStepperValue,\n      steps,\n    });\n  const { from: transitionFromIndex, to: transitionToIndex } =\n    useStepperTransition(currentIndex);\n\n  useDuplicateStepWarning(steps);\n\n  const context = React.useMemo<StepperContextValue>(\n    () => ({\n      value: currentValue,\n      orientation,\n      steps,\n      isExplicitMode,\n      currentIndex,\n      transitionFromIndex,\n      transitionToIndex,\n      totalSteps: steps.length,\n      registerStep,\n      unregisterStep,\n      setValue: setStepperValue,\n      getStepIndex: (stepValue) =>\n        steps.findIndex((step) => step.value === stepValue),\n      getTriggerId: (stepValue) => `${id}-trigger-${getSafeId(stepValue)}`,\n      getContentId: (stepValue) => `${id}-content-${getSafeId(stepValue)}`,\n      canGoPrevious,\n      canGoNext,\n      goPrevious,\n      goNext,\n    }),\n    [\n      canGoNext,\n      canGoPrevious,\n      currentValue,\n      currentIndex,\n      transitionFromIndex,\n      transitionToIndex,\n      goNext,\n      goPrevious,\n      id,\n      isExplicitMode,\n      orientation,\n      registerStep,\n      setStepperValue,\n      steps,\n      unregisterStep,\n    ]\n  );\n\n  return (\n    <StepperContext.Provider value={context}>\n      <div\n        data-slot=\"stepper\"\n        data-orientation={orientation}\n        className={cn(\"flex flex-col gap-6\", className)}\n        {...props}\n      >\n        {children}\n      </div>\n    </StepperContext.Provider>\n  );\n}\n\n// ----------------------------------------------------------------------------\n// List\n// ----------------------------------------------------------------------------\n\nfunction StepperList({\n  className,\n  \"aria-label\": ariaLabel = \"Progress steps\",\n  children,\n  ...props\n}: StepperListProps) {\n  const { orientation } = useStepperContext(\"StepperList\");\n\n  return (\n    <StepperListContext.Provider value={true}>\n      <ol\n        aria-label={props[\"aria-labelledby\"] ? undefined : ariaLabel}\n        data-slot=\"stepper-list\"\n        data-orientation={orientation}\n        className={cn(\n          \"flex min-w-0\",\n          \"data-[orientation=horizontal]:w-full data-[orientation=horizontal]:gap-0 data-[orientation=horizontal]:overflow-x-auto data-[orientation=horizontal]:pb-2\",\n          \"data-[orientation=vertical]:flex-col data-[orientation=vertical]:gap-4\",\n          \"[&>li:last-child_[data-slot=stepper-separator]]:hidden\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n      </ol>\n    </StepperListContext.Provider>\n  );\n}\n\n// ----------------------------------------------------------------------------\n// Item\n// ----------------------------------------------------------------------------\n\nfunction StepperItem<TValue extends StepperValue = StepperValue>({\n  value,\n  completed = false,\n  defaultTrigger = true,\n  disabled = false,\n  error = false,\n  separator = true,\n  className,\n  style,\n  children,\n  ...props\n}: StepperItemProps<TValue>) {\n  const {\n    value: currentValue,\n    orientation,\n    steps,\n    isExplicitMode,\n    transitionFromIndex,\n    transitionToIndex,\n    registerStep,\n    unregisterStep,\n    setValue,\n    getStepIndex,\n    getTriggerId,\n    getContentId,\n  } = useStepperContext(\"StepperItem\");\n  const registrationId = React.useId();\n  const isInsideStepperList = useStepperListContext();\n  const index = getStepIndex(value);\n  const step = getStepByValue(steps, value);\n  const isDisabled = step?.disabled ?? disabled;\n  const currentIndex =\n    currentValue === undefined ? -1 : getStepIndex(currentValue);\n  const isActive = currentValue === value;\n  const stepPosition: StepperStepPosition =\n    currentIndex < 0 || index < 0\n      ? \"next\"\n      : index < currentIndex\n        ? \"previous\"\n        : index === currentIndex\n          ? \"current\"\n          : \"next\";\n  const stepState: StepperStepState = isDisabled\n    ? \"disabled\"\n    : error\n      ? \"error\"\n      : isActive\n        ? \"active\"\n        : completed\n          ? \"completed\"\n          : \"inactive\";\n  const renderDefaultTrigger = defaultTrigger;\n  const isLastStep = index >= 0 && index === steps.length - 1;\n  const shouldRenderSeparator =\n    isInsideStepperList && separator && !isLastStep;\n  const separatorTransitionDelay = getStepTransitionDelay({\n    from: transitionFromIndex,\n    index,\n    to: transitionToIndex,\n  });\n  const itemStyle = {\n    ...style,\n    \"--stepper-separator-delay\": `${separatorTransitionDelay}ms`,\n  } as React.CSSProperties;\n\n  React.useLayoutEffect(() => {\n    if (!isInsideStepperList || isExplicitMode) {\n      return;\n    }\n\n    registerStep({\n      id: registrationId,\n      value,\n      disabled,\n    });\n\n    return () => unregisterStep(registrationId);\n  }, [\n    disabled,\n    isExplicitMode,\n    isInsideStepperList,\n    registerStep,\n    registrationId,\n    unregisterStep,\n    value,\n  ]);\n\n  React.useEffect(() => {\n    if (!isDevelopment || isInsideStepperList) {\n      return;\n    }\n\n    const timeout = window.setTimeout(() => {\n      warnDev(\n        `StepperItem with value \"${value}\" must be rendered inside StepperList to participate in step order.`\n      );\n    }, 0);\n\n    return () => window.clearTimeout(timeout);\n  }, [isInsideStepperList, value]);\n\n  React.useEffect(() => {\n    if (\n      !isDevelopment ||\n      !isInsideStepperList ||\n      index >= 0\n    ) {\n      return;\n    }\n\n    const timeout = window.setTimeout(() => {\n      warnDev(\n        `StepperItem with value \"${value}\" could not be found in the Stepper order. Check that it is rendered inside StepperList. For dynamic or conditional step order, pass an explicit steps prop to Stepper.`\n      );\n    }, 0);\n\n    return () => window.clearTimeout(timeout);\n  }, [index, isInsideStepperList, value]);\n\n  const itemContext = React.useMemo<StepperItemContextValue>(\n    () => ({\n      value,\n      index,\n      disabled: isDisabled,\n      completed,\n      isActive,\n      stepState,\n      stepPosition,\n      orientation,\n      setValue,\n      triggerId: getTriggerId(value),\n      contentId: getContentId(value),\n    }),\n    [\n      value,\n      index,\n      isDisabled,\n      completed,\n      isActive,\n      stepState,\n      stepPosition,\n      orientation,\n      setValue,\n      getTriggerId,\n      getContentId,\n    ]\n  );\n\n  return (\n    <li\n      data-slot=\"stepper-item\"\n      data-orientation={orientation}\n      data-state={stepState}\n      data-position={stepPosition}\n      data-disabled={isDisabled ? \"\" : undefined}\n      data-error={error ? \"\" : undefined}\n      data-completed={completed ? \"\" : undefined}\n      className={cn(\n        \"group/stepper-item relative flex min-w-0\",\n        \"[--stepper-indicator-size:1.75rem] [--stepper-separator-offset:calc(var(--stepper-indicator-size)_/_2)] [--stepper-separator-y:calc(var(--stepper-indicator-size)_/_2)] sm:[--stepper-indicator-size:2.25rem]\",\n        \"data-[orientation=horizontal]:min-w-16 data-[orientation=horizontal]:flex-1 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:items-center sm:data-[orientation=horizontal]:min-w-28\",\n        \"data-[orientation=vertical]:items-start data-[orientation=vertical]:gap-3\",\n        className\n      )}\n      style={itemStyle}\n      {...props}\n    >\n      <StepperItemContext.Provider value={itemContext}>\n        {renderDefaultTrigger ? (\n          <>\n            <StepperTrigger>\n              <StepperIndicator />\n              <StepperLabel>{children}</StepperLabel>\n            </StepperTrigger>\n            {shouldRenderSeparator ? <StepperSeparator /> : null}\n          </>\n        ) : (\n          <>\n            {children}\n            {shouldRenderSeparator ? <StepperSeparator /> : null}\n          </>\n        )}\n      </StepperItemContext.Provider>\n    </li>\n  );\n}\n\n// ----------------------------------------------------------------------------\n// Trigger\n// ----------------------------------------------------------------------------\n\nfunction StepperTrigger({\n  asChild = false,\n  className,\n  children,\n  disabled,\n  onClick,\n  onKeyDown,\n  tabIndex,\n  ...props\n}: StepperTriggerProps) {\n  const {\n    value,\n    disabled: itemDisabled,\n    isActive,\n    stepState,\n    orientation,\n    setValue,\n    triggerId,\n    contentId,\n  } = useStepperItemContext(\"StepperTrigger\");\n  const { steps, getTriggerId } = useStepperContext(\"StepperTrigger\");\n  const isDisabled = itemDisabled || disabled;\n  const Comp = asChild ? Slot : \"button\";\n\n  return (\n    <Comp\n      id={triggerId}\n      type={asChild ? undefined : \"button\"}\n      aria-current={isActive ? \"step\" : undefined}\n      aria-controls={isActive ? contentId : undefined}\n      aria-disabled={isDisabled ? true : undefined}\n      disabled={asChild ? undefined : isDisabled}\n      tabIndex={asChild && isDisabled ? -1 : tabIndex}\n      data-slot=\"stepper-trigger\"\n      data-state={stepState}\n      data-disabled={isDisabled ? \"\" : undefined}\n      className={cn(\n        \"group inline-flex min-h-10 min-w-0 items-center gap-2 rounded-lg text-left text-sm font-medium outline-none\",\n        \"text-muted-foreground transition-[color,background-color,border-color,box-shadow,transform] hover:text-foreground active:scale-[0.96]\",\n        \"focus-visible:ring-ring/50 focus-visible:ring-[3px] focus-visible:outline-none\",\n        \"disabled:pointer-events-none disabled:opacity-50\",\n        \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n        \"data-[state=active]:text-foreground\",\n        \"data-[state=completed]:text-foreground\",\n        \"data-[state=error]:text-destructive\",\n        orientation === \"horizontal\" && \"w-full flex-col items-center text-center\",\n        orientation === \"vertical\" && \"justify-start\",\n        className\n      )}\n      onClick={(event: React.MouseEvent<HTMLButtonElement>) => {\n        onClick?.(event);\n\n        if (isDisabled) {\n          event.preventDefault();\n          return;\n        }\n\n        if (!event.defaultPrevented) {\n          setValue(value);\n        }\n      }}\n      onKeyDown={(event: React.KeyboardEvent<HTMLButtonElement>) => {\n        onKeyDown?.(event);\n\n        if (event.defaultPrevented || isDisabled) {\n          return;\n        }\n\n        const targetStepValue = getKeyboardNavigationStepValue({\n          key: event.key,\n          orientation,\n          steps,\n          value,\n        });\n\n        if (!targetStepValue || targetStepValue === value) {\n          return;\n        }\n\n        const targetTrigger = document.getElementById(\n          getTriggerId(targetStepValue)\n        );\n\n        if (targetTrigger instanceof HTMLElement) {\n          event.preventDefault();\n          targetTrigger.focus();\n        }\n      }}\n      {...props}\n    >\n      {children}\n    </Comp>\n  );\n}\n\nfunction StepperIndicator({\n  className,\n  children,\n  ...props\n}: StepperIndicatorProps) {\n  const { index, stepState } = useStepperItemContext(\"StepperIndicator\");\n  const stepNumber = index >= 0 ? index + 1 : undefined;\n  const content =\n    children !== undefined\n      ? children\n      : stepState === \"error\"\n        ? \"!\"\n        : stepState === \"completed\"\n          ? \"\\u2713\"\n          : stepNumber\n            ? stepNumber\n            : null;\n\n  return (\n    <>\n      {stepNumber ? (\n        <span className=\"sr-only\">Step {stepNumber}:</span>\n      ) : null}\n      <span\n        aria-hidden=\"true\"\n        data-slot=\"stepper-indicator\"\n        className={cn(\n          \"flex size-(--stepper-indicator-size) shrink-0 items-center justify-center rounded-full border border-border bg-background text-xs font-semibold text-muted-foreground shadow-sm\",\n          \"transition-[color,background-color,border-color,box-shadow,transform]\",\n          \"group-hover:border-foreground/30\",\n          \"group-data-[state=active]:border-primary group-data-[state=active]:bg-primary group-data-[state=active]:text-primary-foreground group-data-[state=active]:shadow-md\",\n          \"group-data-[state=completed]:border-primary group-data-[state=completed]:bg-primary group-data-[state=completed]:text-primary-foreground\",\n          \"group-data-[state=error]:border-destructive group-data-[state=error]:bg-destructive group-data-[state=error]:text-destructive-foreground\",\n          \"group-data-[position=previous]:text-foreground\",\n          \"[transition-delay:var(--stepper-separator-delay)] motion-reduce:[transition-delay:0ms]\",\n          \"[&>svg]:size-3.5 [&>svg]:shrink-0 sm:[&>svg]:size-4\",\n          className\n        )}\n        {...props}\n      >\n        {content}\n      </span>\n    </>\n  );\n}\n\nfunction StepperLabel({ className, ...props }: StepperLabelProps) {\n  const { orientation } = useStepperItemContext(\"StepperLabel\");\n\n  return (\n    <span\n      data-slot=\"stepper-label\"\n      className={cn(\n        \"min-w-0 text-xs leading-tight font-medium sm:text-sm\",\n        orientation === \"horizontal\" && \"max-w-40 text-balance\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction StepperDescription({ className, ...props }: StepperDescriptionProps) {\n  const { orientation } = useStepperItemContext(\"StepperDescription\");\n\n  return (\n    <span\n      data-slot=\"stepper-description\"\n      className={cn(\n        \"text-xs leading-snug font-normal text-muted-foreground\",\n        orientation === \"horizontal\" && \"max-w-44 text-balance\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction StepperSeparator({ className, ...props }: StepperSeparatorProps) {\n  const { orientation } = useStepperItemContext(\"StepperSeparator\");\n\n  return (\n    <span\n      aria-hidden=\"true\"\n      data-slot=\"stepper-separator\"\n      className={cn(\n        \"overflow-hidden bg-muted-foreground/25 after:absolute after:inset-0 after:bg-primary after:content-['']\",\n        \"after:transition-transform after:duration-[220ms] after:ease-out after:[transition-delay:var(--stepper-separator-delay)] motion-reduce:after:transition-none motion-reduce:after:[transition-delay:0ms]\",\n        orientation === \"horizontal\" &&\n          \"absolute left-[calc(50%_+_var(--stepper-separator-offset))] right-[calc(-50%_+_var(--stepper-separator-offset))] top-(--stepper-separator-y) h-px after:origin-left after:scale-x-0 group-data-[completed]/stepper-item:after:scale-x-100 group-data-[position=previous]/stepper-item:after:scale-x-100 group-data-[state=completed]/stepper-item:after:scale-x-100\",\n        orientation === \"vertical\" &&\n          \"absolute left-[calc(var(--stepper-indicator-size)_/_2)] top-[calc(var(--stepper-indicator-size)_+_0.5rem)] h-[calc(100%_-_var(--stepper-indicator-size)_+_0.75rem)] w-px after:origin-top after:scale-y-0 group-data-[completed]/stepper-item:after:scale-y-100 group-data-[position=previous]/stepper-item:after:scale-y-100 group-data-[state=completed]/stepper-item:after:scale-y-100\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\n// ----------------------------------------------------------------------------\n// Content\n// ----------------------------------------------------------------------------\n\nfunction StepperContent<TValue extends StepperValue = StepperValue>({\n  value,\n  forceMount = false,\n  keepMounted = false,\n  asChild = false,\n  className,\n  children,\n  ...props\n}: StepperContentProps<TValue>) {\n  const {\n    value: currentValue,\n    steps,\n    getTriggerId,\n    getContentId,\n  } = useStepperContext(\"StepperContent\");\n  const isActive = currentValue === value;\n  const hasMatchingStep = steps.some((step) => step.value === value);\n  const shouldKeepMounted = forceMount || keepMounted;\n\n  React.useEffect(() => {\n    if (!isDevelopment || hasMatchingStep) {\n      return;\n    }\n\n    const timeout = window.setTimeout(() => {\n      warnDev(\n        `StepperContent value \"${value}\" does not match any StepperItem. Content values should map to a step value.`\n      );\n    }, 0);\n\n    return () => window.clearTimeout(timeout);\n  }, [hasMatchingStep, value]);\n\n  if (!shouldKeepMounted && !isActive) {\n    return null;\n  }\n\n  const Comp = asChild ? Slot : \"div\";\n\n  return (\n    <Comp\n      id={getContentId(value)}\n      role=\"region\"\n      aria-labelledby={getTriggerId(value)}\n      data-slot=\"stepper-content\"\n      data-state={isActive ? \"active\" : \"inactive\"}\n      hidden={shouldKeepMounted ? !isActive : undefined}\n      className={cn(\n        \"rounded-lg border border-border/70 bg-muted/25 p-4 text-sm text-foreground shadow-sm\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </Comp>\n  );\n}\n\n// ----------------------------------------------------------------------------\n// Navigation\n// ----------------------------------------------------------------------------\n\nfunction StepperPrevious({\n  asChild = false,\n  className,\n  children = \"Previous\",\n  disabled,\n  onBeforePrevious,\n  onClick,\n  tabIndex,\n  ...props\n}: StepperPreviousProps) {\n  const { canGoPrevious, goPrevious } = useStepperContext(\"StepperPrevious\");\n  const { handleClick, isDisabled } = useNavigationButton({\n    canNavigate: canGoPrevious,\n    disabled,\n    navigate: goPrevious,\n    onBeforeNavigate: onBeforePrevious,\n  });\n  const Comp = asChild ? Slot : \"button\";\n\n  return (\n    <Comp\n      type={asChild ? undefined : \"button\"}\n      disabled={asChild ? undefined : isDisabled}\n      aria-disabled={isDisabled ? true : undefined}\n      tabIndex={asChild && isDisabled ? -1 : tabIndex}\n      data-slot=\"stepper-previous\"\n      data-disabled={isDisabled ? \"\" : undefined}\n      className={\n        asChild\n          ? className\n          : cn(\n              \"inline-flex h-9 min-w-24 items-center justify-center gap-2 rounded-none border border-border bg-background px-3 text-sm font-medium text-foreground\",\n              \"transition-[color,background-color,border-color,box-shadow,transform] hover:border-foreground/20 hover:bg-muted hover:text-foreground active:scale-[0.97]\",\n              \"focus-visible:ring-ring/50 focus-visible:ring-[3px] focus-visible:outline-none\",\n              \"disabled:pointer-events-none disabled:opacity-50\",\n              \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n              \"[&>svg]:size-4 [&>svg]:shrink-0\",\n              className\n            )\n      }\n      onClick={(event: React.MouseEvent<HTMLButtonElement>) =>\n        handleClick(event, onClick)\n      }\n      {...props}\n    >\n      {children}\n    </Comp>\n  );\n}\n\nfunction StepperNext({\n  asChild = false,\n  className,\n  children = \"Next\",\n  disabled,\n  onBeforeNext,\n  onClick,\n  tabIndex,\n  ...props\n}: StepperNextProps) {\n  const { canGoNext, goNext } = useStepperContext(\"StepperNext\");\n  const { handleClick, isDisabled } = useNavigationButton({\n    canNavigate: canGoNext,\n    disabled,\n    navigate: goNext,\n    onBeforeNavigate: onBeforeNext,\n  });\n  const Comp = asChild ? Slot : \"button\";\n\n  return (\n    <Comp\n      type={asChild ? undefined : \"button\"}\n      disabled={asChild ? undefined : isDisabled}\n      aria-disabled={isDisabled ? true : undefined}\n      tabIndex={asChild && isDisabled ? -1 : tabIndex}\n      data-slot=\"stepper-next\"\n      data-disabled={isDisabled ? \"\" : undefined}\n      className={\n        asChild\n          ? className\n          : cn(\n              \"inline-flex h-9 min-w-24 items-center justify-center gap-2 rounded-none border border-primary bg-primary px-3 text-sm font-medium text-primary-foreground\",\n              \"transition-[background-color,border-color,box-shadow,transform] hover:bg-primary/90 active:scale-[0.97]\",\n              \"focus-visible:ring-ring/50 focus-visible:ring-[3px] focus-visible:outline-none\",\n              \"disabled:pointer-events-none disabled:opacity-50\",\n              \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n              \"[&>svg]:size-4 [&>svg]:shrink-0\",\n              className\n            )\n      }\n      onClick={(event: React.MouseEvent<HTMLButtonElement>) =>\n        handleClick(event, onClick)\n      }\n      {...props}\n    >\n      {children}\n    </Comp>\n  );\n}\n\n// ----------------------------------------------------------------------------\n// Exports\n// ----------------------------------------------------------------------------\n\nsetDisplayName(Stepper, \"Stepper\");\nsetDisplayName(StepperList, \"StepperList\");\nsetDisplayName(StepperItem, \"StepperItem\");\nsetDisplayName(StepperTrigger, \"StepperTrigger\");\nsetDisplayName(StepperIndicator, \"StepperIndicator\");\nsetDisplayName(StepperLabel, \"StepperLabel\");\nsetDisplayName(StepperDescription, \"StepperDescription\");\nsetDisplayName(StepperSeparator, \"StepperSeparator\");\nsetDisplayName(StepperContent, \"StepperContent\");\nsetDisplayName(StepperPrevious, \"StepperPrevious\");\nsetDisplayName(StepperNext, \"StepperNext\");\n\nexport {\n  Stepper,\n  StepperContent,\n  StepperDescription,\n  StepperIndicator,\n  StepperItem,\n  StepperLabel,\n  StepperList,\n  StepperNext,\n  StepperPrevious,\n  StepperSeparator,\n  StepperTrigger,\n  useStepper,\n  useStepperItem,\n};\n\nexport type {\n  StepperApi,\n  StepperButtonProps,\n  StepperContentProps,\n  StepperDescriptionProps,\n  StepperIndicatorProps,\n  StepperItemApi,\n  StepperItemProps,\n  StepperLabelProps,\n  StepperListProps,\n  StepperNavigationGuard,\n  StepperNextProps,\n  StepperOrientation,\n  StepperPreviousProps,\n  StepperProps,\n  StepperSeparatorProps,\n  StepperStep,\n  StepperStepInput,\n  StepperStepPosition,\n  StepperStepState,\n  StepperStepsValue,\n  StepperTriggerProps,\n  StepperValue,\n};\n",
      "type": "registry:ui",
      "target": "@ui/stepper.tsx"
    },
    {
      "path": "registry/default/examples/stepper-intent-onboarding.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n  ArrowRight,\n  BookOpen,\n  BriefcaseBusiness,\n  Check,\n  Circle,\n  CircleHelp,\n  Home,\n  ImagePlus,\n  KeyRound,\n  Laptop,\n  ListChecks,\n  LoaderCircle,\n  Mail,\n  Monitor,\n  Plane,\n  School,\n  Sparkles,\n  SquareCheckBig,\n  UsersRound,\n  type LucideIcon,\n} from \"lucide-react\";\nimport {\n  useForm,\n  useWatch,\n  type FieldPath,\n  type UseFormRegisterReturn,\n} from \"react-hook-form\";\nimport { SiGoogle } from \"react-icons/si\";\nimport { z } from \"zod/v3\";\n\nimport { StepperLogo } from \"@/components/stepper-logo\";\nimport { Button } from \"@/components/ui/button\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport {\n  Field,\n  FieldDescription,\n  FieldError,\n  FieldLabel,\n} from \"@/components/ui/field\";\nimport { Input } from \"@/components/ui/input\";\nimport { Separator } from \"@/components/ui/separator\";\nimport {\n  Stepper,\n  StepperContent,\n  StepperItem,\n  StepperList,\n} from \"@/components/ui/stepper\";\nimport { cn } from \"@/lib/utils\";\n\nconst emailStepSchema = z.object({\n  email: z.string().trim().email(\"Enter a valid work email.\"),\n});\n\nconst verificationStepSchema = z.object({\n  code: z\n    .string()\n    .trim()\n    .regex(/^\\d{6}$/, \"Enter the 6-digit verification code.\"),\n});\n\nconst profileStepSchema = z.object({\n  name: z.string().trim().min(2, \"Enter your name.\"),\n  password: z.string().min(8, \"Use at least 8 characters.\"),\n});\n\nconst intentStepSchema = z.object({\n  intent: z.enum([\"work\", \"personal\", \"school\"], {\n    required_error: \"Choose what you are setting up.\",\n  }),\n});\n\nconst collaborationStepSchema = z.object({\n  collaboration: z.enum([\"with-others\", \"on-my-own\"], {\n    required_error: \"Choose a collaboration mode.\",\n  }),\n});\n\nconst onboardingStepValues = [\n  \"account\",\n  \"verify\",\n  \"profile\",\n  \"intent\",\n  \"collaboration\",\n  \"interests\",\n  \"generating\",\n  \"workspace\",\n] as const;\n\ntype OnboardingStep = (typeof onboardingStepValues)[number];\ntype IntentValue = z.infer<typeof intentStepSchema>[\"intent\"];\ntype CollaborationValue = z.infer<\n  typeof collaborationStepSchema\n>[\"collaboration\"];\ntype InterestValue =\n  | \"career\"\n  | \"books\"\n  | \"todo\"\n  | \"site\"\n  | \"travel\"\n  | \"projects\"\n  | \"finance\"\n  | \"food\"\n  | \"hobbies\"\n  | \"habits\";\n\ntype IntentOnboardingValues = {\n  email: string;\n  code: string;\n  name: string;\n  password: string;\n  intent?: IntentValue;\n  collaboration?: CollaborationValue;\n  interests: InterestValue[];\n  marketingOptOut: boolean;\n};\n\ntype StepDefinition = {\n  value: OnboardingStep;\n  label: string;\n};\n\nconst onboardingSteps = [\n  { value: \"account\", label: \"Create account\" },\n  { value: \"verify\", label: \"Verify email\" },\n  { value: \"profile\", label: \"Create profile\" },\n  { value: \"intent\", label: \"Choose intent\" },\n  { value: \"collaboration\", label: \"Choose collaboration\" },\n  { value: \"interests\", label: \"Choose interests\" },\n  { value: \"generating\", label: \"Prepare setup\" },\n  { value: \"workspace\", label: \"Signed in\" },\n] satisfies StepDefinition[];\n\nconst intentOptions = [\n  {\n    value: \"work\",\n    title: \"For work\",\n    description: \"Track projects, goals, and meeting notes\",\n    icon: BriefcaseBusiness,\n  },\n  {\n    value: \"personal\",\n    title: \"For personal life\",\n    description: \"Write better, think more clearly, stay organized\",\n    icon: Home,\n  },\n  {\n    value: \"school\",\n    title: \"For school\",\n    description: \"Keep notes, research, and tasks in one place\",\n    icon: School,\n  },\n] satisfies Array<{\n  value: IntentValue;\n  title: string;\n  description: string;\n  icon: LucideIcon;\n}>;\n\nconst collaborationOptions = [\n  {\n    value: \"with-others\",\n    title: \"With others\",\n    description: \"Plan travel, household chores, group activities\",\n    icon: UsersRound,\n  },\n  {\n    value: \"on-my-own\",\n    title: \"On my own\",\n    description: \"Manage expenses, track hobbies, stay organized\",\n    icon: CircleHelp,\n  },\n] satisfies Array<{\n  value: CollaborationValue;\n  title: string;\n  description: string;\n  icon: LucideIcon;\n}>;\n\nconst interestOptions = [\n  { value: \"career\", label: \"Career building\", icon: BriefcaseBusiness },\n  { value: \"books\", label: \"Books and media\", icon: Monitor },\n  { value: \"todo\", label: \"To-do list\", icon: ListChecks },\n  { value: \"site\", label: \"Site or blog\", icon: Laptop },\n  { value: \"travel\", label: \"Travel\", icon: Plane },\n  { value: \"projects\", label: \"Project tracking\", icon: SquareCheckBig },\n  { value: \"finance\", label: \"Personal finance\", icon: Circle },\n  { value: \"food\", label: \"Food and nutrition\", icon: Home },\n  { value: \"hobbies\", label: \"Hobbies\", icon: BookOpen },\n  { value: \"habits\", label: \"Habit tracking\", icon: Check },\n] satisfies Array<{\n  value: InterestValue;\n  label: string;\n  icon: LucideIcon;\n}>;\n\nconst stepFields = {\n  account: [\"email\"],\n  verify: [\"code\"],\n  profile: [\"name\", \"password\"],\n  intent: [\"intent\"],\n  collaboration: [\"collaboration\"],\n  interests: [],\n  generating: [],\n  workspace: [],\n} satisfies Record<OnboardingStep, FieldPath<IntentOnboardingValues>[]>;\n\nfunction StepperIntentOnboardingExample() {\n  const [step, setStep] = React.useState<OnboardingStep>(\"account\");\n  const [completedSteps, setCompletedSteps] = React.useState<\n    Partial<Record<OnboardingStep, boolean>>\n  >({});\n  const [isGenerating, setIsGenerating] = React.useState(false);\n  const generationTimeoutRef = React.useRef<number | null>(null);\n  const form = useForm<IntentOnboardingValues>({\n    mode: \"onChange\",\n    defaultValues: {\n      email: \"\",\n      code: \"\",\n      name: \"\",\n      password: \"\",\n      intent: undefined,\n      collaboration: undefined,\n      interests: [],\n      marketingOptOut: false,\n    },\n  });\n  const watchedValues = useWatch({ control: form.control });\n  const values = React.useMemo<IntentOnboardingValues>(\n    () => ({\n      email: watchedValues.email ?? \"\",\n      code: watchedValues.code ?? \"\",\n      name: watchedValues.name ?? \"\",\n      password: watchedValues.password ?? \"\",\n      intent: watchedValues.intent,\n      collaboration: watchedValues.collaboration,\n      interests: watchedValues.interests ?? [],\n      marketingOptOut: watchedValues.marketingOptOut ?? false,\n    }),\n    [\n      watchedValues.code,\n      watchedValues.collaboration,\n      watchedValues.email,\n      watchedValues.intent,\n      watchedValues.interests,\n      watchedValues.marketingOptOut,\n      watchedValues.name,\n      watchedValues.password,\n    ]\n  );\n  const currentIndex = getVisibleStepIndex(step, values);\n  const totalVisibleSteps = getVisibleSteps(values).length;\n  const progress = Math.round(((currentIndex + 1) / totalVisibleSteps) * 100);\n\n  React.useEffect(() => {\n    return () => {\n      if (generationTimeoutRef.current) {\n        window.clearTimeout(generationTimeoutRef.current);\n      }\n    };\n  }, []);\n\n  async function continueFromStep() {\n    const isValid = validateCurrentStep(step, form);\n\n    if (!isValid) {\n      return;\n    }\n\n    setCompletedSteps((current) => ({ ...current, [step]: true }));\n\n    if (step === \"interests\") {\n      startGeneration();\n      return;\n    }\n\n    const nextStep = getNextStep(step, values);\n\n    if (nextStep) {\n      setStep(nextStep);\n    }\n  }\n\n  function continueWithProvider(provider: string) {\n    const providerEmail =\n      provider === \"Google\" ? \"alex.smith@example.com\" : \"alex@example.com\";\n\n    form.clearErrors([\"email\", \"code\"]);\n    form.setValue(\"email\", providerEmail, {\n      shouldDirty: true,\n      shouldTouch: true,\n      shouldValidate: true,\n    });\n    setCompletedSteps((current) => ({\n      ...current,\n      account: true,\n      verify: true,\n    }));\n    setStep(\"profile\");\n  }\n\n  function resetFlow() {\n    if (generationTimeoutRef.current) {\n      window.clearTimeout(generationTimeoutRef.current);\n      generationTimeoutRef.current = null;\n    }\n\n    setIsGenerating(false);\n    setCompletedSteps({});\n    form.reset();\n    setStep(\"account\");\n  }\n\n  function selectIntent(intent: IntentValue) {\n    form.clearErrors(\"intent\");\n    form.setValue(\"intent\", intent, {\n      shouldDirty: true,\n      shouldTouch: true,\n      shouldValidate: true,\n    });\n    setCompletedSteps((current) => ({\n      ...current,\n      intent: false,\n      collaboration: false,\n    }));\n  }\n\n  function selectCollaboration(collaboration: CollaborationValue) {\n    form.clearErrors(\"collaboration\");\n    form.setValue(\"collaboration\", collaboration, {\n      shouldDirty: true,\n      shouldTouch: true,\n      shouldValidate: true,\n    });\n  }\n\n  function toggleInterest(interest: InterestValue) {\n    const currentInterests = values.interests;\n    const nextInterests = currentInterests.includes(interest)\n      ? currentInterests.filter((item) => item !== interest)\n      : [...currentInterests, interest];\n\n    form.setValue(\"interests\", nextInterests, {\n      shouldDirty: true,\n      shouldTouch: true,\n    });\n  }\n\n  function skipInterests() {\n    form.setValue(\"interests\", [], {\n      shouldDirty: true,\n      shouldTouch: true,\n    });\n    setCompletedSteps((current) => ({ ...current, interests: true }));\n    startGeneration();\n  }\n\n  function startGeneration() {\n    setIsGenerating(true);\n    setStep(\"generating\");\n\n    if (generationTimeoutRef.current) {\n      window.clearTimeout(generationTimeoutRef.current);\n    }\n\n    generationTimeoutRef.current = window.setTimeout(() => {\n      setIsGenerating(false);\n      setCompletedSteps((current) => ({\n        ...current,\n        interests: true,\n        generating: true,\n        workspace: true,\n      }));\n      setStep(\"workspace\");\n    }, 700);\n  }\n\n  return (\n    <Stepper\n      value={step}\n      onValueChange={(nextStep) => setStep(nextStep as OnboardingStep)}\n      className=\"min-w-0 gap-0 overflow-hidden rounded-xl border border-border bg-background text-foreground shadow-sm\"\n    >\n      <div className=\"h-1 bg-muted\">\n        <div\n          className=\"h-full bg-foreground transition-[width] duration-300 ease-out\"\n          style={{ width: `${progress}%` }}\n        />\n      </div>\n\n      <div className=\"flex min-h-[560px] flex-col\">\n        <HiddenStepList completedSteps={completedSteps} values={values} />\n\n        <StepperContent value=\"account\" className=\"border-0 bg-transparent p-0 shadow-none\">\n          <CenteredStage>\n            <AuthPanel\n              email={values.email}\n              error={form.formState.errors.email?.message}\n              registerEmail={form.register(\"email\", {\n                onChange: () => form.clearErrors(\"email\"),\n              })}\n              onContinue={() => void continueFromStep()}\n              onGoogle={() => continueWithProvider(\"Google\")}\n            />\n          </CenteredStage>\n        </StepperContent>\n\n        <StepperContent value=\"verify\" className=\"border-0 bg-transparent p-0 shadow-none\">\n          <CenteredStage>\n            <VerifyPanel\n              email={values.email}\n              error={form.formState.errors.code?.message}\n              registerCode={form.register(\"code\", {\n                onChange: () => form.clearErrors(\"code\"),\n              })}\n              onContinue={() => void continueFromStep()}\n            />\n          </CenteredStage>\n        </StepperContent>\n\n        <StepperContent value=\"profile\" className=\"border-0 bg-transparent p-0 shadow-none\">\n          <CenteredStage>\n            <ProfilePanel\n              values={values}\n              errors={{\n                name: form.formState.errors.name?.message,\n                password: form.formState.errors.password?.message,\n              }}\n              registerName={form.register(\"name\", {\n                onChange: () => form.clearErrors(\"name\"),\n              })}\n              registerPassword={form.register(\"password\", {\n                onChange: () => form.clearErrors(\"password\"),\n              })}\n              marketingOptOut={values.marketingOptOut}\n              onMarketingChange={(checked) =>\n                form.setValue(\"marketingOptOut\", checked, {\n                  shouldDirty: true,\n                  shouldTouch: true,\n                })\n              }\n              onContinue={() => void continueFromStep()}\n            />\n          </CenteredStage>\n        </StepperContent>\n\n        <StepperContent value=\"intent\" className=\"border-0 bg-transparent p-0 shadow-none\">\n          <CenteredStage>\n            <IntentPanel\n              value={values.intent}\n              error={form.formState.errors.intent?.message}\n              onSelect={selectIntent}\n              onContinue={() => void continueFromStep()}\n            />\n          </CenteredStage>\n        </StepperContent>\n\n        <StepperContent\n          value=\"collaboration\"\n          className=\"border-0 bg-transparent p-0 shadow-none\"\n        >\n          <CenteredStage>\n            <CollaborationPanel\n              value={values.collaboration}\n              error={form.formState.errors.collaboration?.message}\n              onSelect={selectCollaboration}\n              onContinue={() => void continueFromStep()}\n            />\n          </CenteredStage>\n        </StepperContent>\n\n        <StepperContent value=\"interests\" className=\"border-0 bg-transparent p-0 shadow-none\">\n          <CenteredStage>\n            <InterestsPanel\n              selectedInterests={values.interests}\n              onToggleInterest={toggleInterest}\n              onContinue={() => void continueFromStep()}\n              onSkip={skipInterests}\n            />\n          </CenteredStage>\n        </StepperContent>\n\n        <StepperContent value=\"generating\" className=\"border-0 bg-transparent p-0 shadow-none\">\n          <CenteredStage>\n            <GeneratingPanel values={values} isGenerating={isGenerating} />\n          </CenteredStage>\n        </StepperContent>\n\n        <StepperContent value=\"workspace\" className=\"border-0 bg-transparent p-0 shadow-none\">\n          <SignedInPanel values={values} onRestart={resetFlow} />\n        </StepperContent>\n      </div>\n    </Stepper>\n  );\n}\n\nfunction HiddenStepList({\n  completedSteps,\n  values,\n}: {\n  completedSteps: Partial<Record<OnboardingStep, boolean>>;\n  values: IntentOnboardingValues;\n}) {\n  return (\n    <StepperList\n      aria-label=\"Intent onboarding flow steps\"\n      className=\"sr-only !w-px !gap-0 !overflow-hidden !pb-0 data-[orientation=horizontal]:!w-px data-[orientation=horizontal]:!gap-0 data-[orientation=horizontal]:!overflow-hidden data-[orientation=horizontal]:!pb-0\"\n    >\n      {onboardingSteps.map((item) => (\n        <StepperItem\n          key={item.value}\n          value={item.value}\n          completed={Boolean(completedSteps[item.value])}\n          disabled={isStepSkipped(item.value, values)}\n        >\n          {item.label}\n        </StepperItem>\n      ))}\n    </StepperList>\n  );\n}\n\nfunction CenteredStage({ children }: { children: React.ReactNode }) {\n  return (\n    <div className=\"flex min-h-[560px] flex-1 items-start justify-center px-5 pb-10 pt-14 sm:px-6 sm:pt-16\">\n      {children}\n    </div>\n  );\n}\n\nfunction AuthPanel({\n  email,\n  error,\n  registerEmail,\n  onContinue,\n  onGoogle,\n}: {\n  email: string;\n  error?: string;\n  registerEmail: UseFormRegisterReturn<\"email\">;\n  onContinue: () => void;\n  onGoogle: () => void;\n}) {\n  return (\n    <div className=\"w-full max-w-[380px]\">\n      <StageHeading\n        title=\"Create your account\"\n        description=\"Start with a focused onboarding flow.\"\n        align=\"center\"\n        logo\n      />\n\n      <ProviderButton onClick={onGoogle} />\n\n      <div className=\"my-5 flex items-center gap-3 text-xs font-medium text-muted-foreground\">\n        <Separator className=\"flex-1 bg-border\" />\n        or\n        <Separator className=\"flex-1 bg-border\" />\n      </div>\n\n      <Field data-invalid={Boolean(error)}>\n        <FieldLabel htmlFor=\"intent-email\" className=\"text-muted-foreground\">\n          Work email\n        </FieldLabel>\n        <div className=\"relative\">\n          <Input\n            id=\"intent-email\"\n            type=\"email\"\n            placeholder=\"Enter your email address...\"\n            autoComplete=\"email\"\n            aria-invalid={Boolean(error)}\n            className=\"h-10 rounded-md border-border bg-background pr-10 text-sm shadow-none focus-visible:ring-ring\"\n            {...registerEmail}\n          />\n          {email ? (\n            <span className=\"absolute top-1/2 right-3 -translate-y-1/2 rounded-full bg-foreground p-0.5 text-background\">\n              <Check className=\"size-3\" />\n            </span>\n          ) : (\n            <Mail className=\"absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground\" />\n          )}\n        </div>\n        {error ? (\n          <FieldError>{error}</FieldError>\n        ) : (\n          <FieldDescription className=\"text-muted-foreground\">\n            Use an organization email to easily collaborate with teammates.\n          </FieldDescription>\n        )}\n      </Field>\n\n      <PrimaryAction className=\"mt-6\" onClick={onContinue}>\n        Continue\n      </PrimaryAction>\n\n      <p className=\"mt-5 text-center text-xs leading-5 text-muted-foreground\">\n        By continuing, you acknowledge that you understand and agree to the{\" \"}\n        <span className=\"underline decoration-border underline-offset-2\">\n          Terms & Conditions\n        </span>{\" \"}\n        and{\" \"}\n        <span className=\"underline decoration-border underline-offset-2\">\n          Privacy Policy\n        </span>\n        .\n      </p>\n    </div>\n  );\n}\n\nfunction VerifyPanel({\n  email,\n  error,\n  registerCode,\n  onContinue,\n}: {\n  email: string;\n  error?: string;\n  registerCode: UseFormRegisterReturn<\"code\">;\n  onContinue: () => void;\n}) {\n  return (\n    <div className=\"w-full max-w-[380px]\">\n      <StageHeading\n        title=\"Check your inbox\"\n        description=\"Use the code sent to your email.\"\n        align=\"center\"\n      />\n\n      <div className=\"mt-7 rounded-lg border border-border bg-muted/40 p-3 text-sm text-muted-foreground\">\n        We sent a verification code to{\" \"}\n        <span className=\"font-medium text-foreground\">{email}</span>.\n      </div>\n\n      <Field data-invalid={Boolean(error)} className=\"mt-5\">\n        <FieldLabel htmlFor=\"intent-code\" className=\"text-muted-foreground\">\n          Verification code\n        </FieldLabel>\n        <Input\n          id=\"intent-code\"\n          inputMode=\"numeric\"\n          placeholder=\"Enter code\"\n          aria-invalid={Boolean(error)}\n          className=\"h-10 rounded-md border-border bg-background font-mono text-sm shadow-none focus-visible:ring-ring\"\n          {...registerCode}\n        />\n        {error ? (\n          <FieldError>{error}</FieldError>\n        ) : (\n          <FieldDescription className=\"text-muted-foreground\">\n            Use 123456 for this demo.\n          </FieldDescription>\n        )}\n      </Field>\n\n      <PrimaryAction className=\"mt-6\" onClick={onContinue}>\n        Continue\n      </PrimaryAction>\n      <p className=\"mt-4 text-center text-sm text-muted-foreground\">\n        Resend in 25s\n      </p>\n    </div>\n  );\n}\n\nfunction ProfilePanel({\n  values,\n  errors,\n  registerName,\n  registerPassword,\n  marketingOptOut,\n  onMarketingChange,\n  onContinue,\n}: {\n  values: IntentOnboardingValues;\n  errors: { name?: string; password?: string };\n  registerName: UseFormRegisterReturn<\"name\">;\n  registerPassword: UseFormRegisterReturn<\"password\">;\n  marketingOptOut: boolean;\n  onMarketingChange: (checked: boolean) => void;\n  onContinue: () => void;\n}) {\n  return (\n    <div className=\"w-full max-w-[380px]\">\n      <StageHeading\n        title=\"Create a profile\"\n        description=\"This is how you'll appear.\"\n        align=\"center\"\n      />\n\n      <div className=\"mt-9 flex flex-col items-center gap-3 text-sm text-muted-foreground\">\n        <div className=\"grid size-14 place-items-center rounded-full border border-border bg-muted/50 text-base font-semibold text-foreground\">\n          {getInitials(values.name || values.email)}\n        </div>\n        <button\n          type=\"button\"\n          className=\"inline-flex items-center gap-1 hover:text-foreground\"\n        >\n          <ImagePlus className=\"size-4\" />\n          Add a photo\n        </button>\n      </div>\n\n      <div className=\"mt-9 grid gap-4\">\n        <Field data-invalid={Boolean(errors.name)}>\n          <FieldLabel htmlFor=\"intent-name\" className=\"text-muted-foreground\">\n            Enter your name\n          </FieldLabel>\n          <Input\n            id=\"intent-name\"\n            placeholder=\"Name\"\n            autoComplete=\"name\"\n            aria-invalid={Boolean(errors.name)}\n            className=\"h-10 rounded-md border-border bg-background text-sm shadow-none focus-visible:ring-ring\"\n            {...registerName}\n          />\n          {errors.name ? <FieldError>{errors.name}</FieldError> : null}\n        </Field>\n\n        <Field data-invalid={Boolean(errors.password)}>\n          <FieldLabel htmlFor=\"intent-password\" className=\"text-muted-foreground\">\n            Set a password\n          </FieldLabel>\n          <div className=\"relative\">\n            <Input\n              id=\"intent-password\"\n              type=\"password\"\n              placeholder=\"Password\"\n              autoComplete=\"new-password\"\n              aria-invalid={Boolean(errors.password)}\n              className=\"h-10 rounded-md border-border bg-background pr-10 text-sm shadow-none focus-visible:ring-ring\"\n              {...registerPassword}\n            />\n            <KeyRound className=\"absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground\" />\n          </div>\n          {errors.password ? (\n            <FieldError>{errors.password}</FieldError>\n          ) : null}\n        </Field>\n      </div>\n\n      <PrimaryAction className=\"mt-9\" onClick={onContinue}>\n        Continue\n      </PrimaryAction>\n\n      <label className=\"mt-4 flex items-start gap-2 text-xs leading-5 text-muted-foreground\">\n        <Checkbox\n          checked={marketingOptOut}\n          onCheckedChange={(checked) => onMarketingChange(checked === true)}\n          className=\"mt-0.5 border-border\"\n        />\n        No, I do not want to receive marketing communications.\n      </label>\n    </div>\n  );\n}\n\nfunction IntentPanel({\n  value,\n  error,\n  onSelect,\n  onContinue,\n}: {\n  value?: IntentValue;\n  error?: string;\n  onSelect: (value: IntentValue) => void;\n  onContinue: () => void;\n}) {\n  return (\n    <div className=\"w-full max-w-[520px]\">\n      <StageHeading\n        title=\"What are you setting up?\"\n        description=\"This helps customize your experience\"\n        align=\"center\"\n      />\n\n      <div className=\"mt-8 grid gap-3\">\n        {intentOptions.map((option) => (\n          <LargeOptionButton\n            key={option.value}\n            active={value === option.value}\n            icon={option.icon}\n            title={option.title}\n            description={option.description}\n            onClick={() => onSelect(option.value)}\n          />\n        ))}\n      </div>\n\n      {error ? (\n        <p className=\"mt-3 text-center text-sm text-destructive\">{error}</p>\n      ) : null}\n\n      <PrimaryAction className=\"mt-7\" onClick={onContinue}>\n        Continue\n      </PrimaryAction>\n    </div>\n  );\n}\n\nfunction CollaborationPanel({\n  value,\n  error,\n  onSelect,\n  onContinue,\n}: {\n  value?: CollaborationValue;\n  error?: string;\n  onSelect: (value: CollaborationValue) => void;\n  onContinue: () => void;\n}) {\n  return (\n    <div className=\"w-full max-w-[500px]\">\n      <StageHeading\n        title=\"How will you work?\"\n        description=\"Pick the mode that best fits this setup\"\n        align=\"center\"\n      />\n\n      <div className=\"mt-8 grid gap-3 sm:grid-cols-2\">\n        {collaborationOptions.map((option) => (\n          <TileOptionButton\n            key={option.value}\n            active={value === option.value}\n            icon={option.icon}\n            title={option.title}\n            description={option.description}\n            onClick={() => onSelect(option.value)}\n          />\n        ))}\n      </div>\n\n      {error ? (\n        <p className=\"mt-3 text-center text-sm text-destructive\">{error}</p>\n      ) : null}\n\n      <PrimaryAction className=\"mt-7\" onClick={onContinue}>\n        Continue\n      </PrimaryAction>\n    </div>\n  );\n}\n\nfunction InterestsPanel({\n  selectedInterests,\n  onToggleInterest,\n  onContinue,\n  onSkip,\n}: {\n  selectedInterests: InterestValue[];\n  onToggleInterest: (value: InterestValue) => void;\n  onContinue: () => void;\n  onSkip: () => void;\n}) {\n  return (\n    <div className=\"w-full max-w-[520px] text-center\">\n      <StageHeading\n        title=\"Choose starter goals\"\n        description=\"Stepper will prepare the optional path after sign-in.\"\n        align=\"center\"\n      />\n\n      <p className=\"mb-3 mt-7 text-xs font-medium text-muted-foreground\">\n        {selectedInterests.length} selected\n      </p>\n\n      <div className=\"flex flex-wrap justify-center gap-2.5\">\n        {interestOptions.map((option) => (\n          <InterestChip\n            key={option.value}\n            option={option}\n            active={selectedInterests.includes(option.value)}\n            onClick={() => onToggleInterest(option.value)}\n          />\n        ))}\n      </div>\n\n      <PrimaryAction className=\"mx-auto mt-10 max-w-[380px]\" onClick={onContinue}>\n        Continue\n      </PrimaryAction>\n      <button\n        type=\"button\"\n        className=\"mx-auto mt-4 block w-full max-w-[380px] rounded-md py-1 text-sm font-medium text-muted-foreground hover:text-foreground\"\n        onClick={onSkip}\n      >\n        Skip for now\n      </button>\n    </div>\n  );\n}\n\nfunction GeneratingPanel({\n  values,\n  isGenerating,\n}: {\n  values: IntentOnboardingValues;\n  isGenerating: boolean;\n}) {\n  const items = [\n    \"Choosing starter pages\",\n    \"Mapping your interests\",\n    \"Preparing a completion checklist\",\n  ];\n\n  return (\n    <div className=\"w-full max-w-[460px] text-center\">\n      <div className=\"mx-auto grid size-14 place-items-center rounded-xl border border-border bg-muted/40 shadow-sm\">\n        <Sparkles className=\"size-6 text-foreground\" />\n      </div>\n      <h2 className=\"mt-6 text-xl font-semibold tracking-tight text-foreground\">\n        Preparing your setup\n      </h2>\n      <p className=\"mt-3 text-sm font-medium text-muted-foreground\">\n        {values.intent\n          ? `Tuned for ${getIntentLabel(values.intent).toLowerCase()}.`\n          : \"Tuned for your workflow.\"}\n      </p>\n\n      <div className=\"mt-8 rounded-xl border border-border bg-muted/30 p-4 text-left\">\n        {items.map((item, index) => (\n          <div key={item} className=\"flex items-center gap-3 py-2\">\n            <span className=\"grid size-7 place-items-center rounded-full bg-background text-muted-foreground\">\n              {index === items.length - 1 && isGenerating ? (\n                <LoaderCircle className=\"size-4 animate-spin\" />\n              ) : (\n                <Check className=\"size-4\" />\n              )}\n            </span>\n            <span className=\"text-sm font-medium text-foreground\">{item}</span>\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n}\n\nfunction SignedInPanel({\n  values,\n  onRestart,\n}: {\n  values: IntentOnboardingValues;\n  onRestart: () => void;\n}) {\n  const selectedLabels = values.interests\n    .map(\n      (interest) =>\n        interestOptions.find((item) => item.value === interest)?.label\n    )\n    .filter(Boolean)\n    .slice(0, 2);\n\n  return (\n    <div className=\"flex min-h-[560px] flex-1 items-center justify-center px-5 py-12 sm:px-6\">\n      <div className=\"w-full max-w-[360px] overflow-hidden rounded-xl border border-border bg-card text-left\">\n        <div className=\"grid h-28 place-items-center border-b border-border bg-background\">\n          <OnboardingLogo className=\"size-12 text-foreground\" />\n        </div>\n\n        <div className=\"p-4 sm:p-5\">\n          <h2 className=\"text-base font-semibold text-foreground\">\n            You&apos;re signed in\n          </h2>\n          <p className=\"mt-2 text-sm leading-6 text-muted-foreground\">\n            Stepper completed the account, intent, and optional setup path\n            {values.email ? ` for ${values.email}` : \"\"}.\n          </p>\n\n          <div className=\"mt-5 grid gap-2 text-sm\">\n            <ChecklistRow checked text=\"Account verified\" />\n            <ChecklistRow checked text={getIntentSummary(values)} />\n            <ChecklistRow\n              checked\n              text={\n                selectedLabels.length > 0\n                  ? `Prepared ${selectedLabels.join(\" and \")}`\n                  : \"Skipped optional goals\"\n              }\n            />\n          </div>\n\n          <PrimaryAction className=\"mt-6\" onClick={onRestart}>\n            Run again\n          </PrimaryAction>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nfunction StageHeading({\n  title,\n  description,\n  align = \"left\",\n  logo = false,\n}: {\n  title: string;\n  description: string;\n  align?: \"left\" | \"center\";\n  logo?: boolean;\n}) {\n  return (\n    <div className={cn(align === \"center\" && \"text-center\")}>\n      {logo ? <OnboardingLogo className=\"mx-auto mb-5 size-10\" /> : null}\n      <h2 className=\"text-xl font-semibold tracking-tight text-foreground sm:text-2xl\">\n        {title}\n      </h2>\n      <p className=\"mt-1.5 text-sm leading-6 text-muted-foreground\">\n        {description}\n      </p>\n    </div>\n  );\n}\n\nfunction OnboardingLogo({ className }: { className?: string }) {\n  return <StepperLogo className={cn(\"size-10 text-foreground\", className)} />;\n}\n\nfunction ProviderButton({ onClick }: { onClick: () => void }) {\n  return (\n    <Button\n      type=\"button\"\n      variant=\"outline\"\n      className=\"relative mt-7 h-9 w-full justify-center rounded-md border-border bg-background text-sm font-medium text-foreground shadow-none hover:bg-muted/60\"\n      onClick={onClick}\n    >\n      <SiGoogle className=\"absolute left-4 size-4 text-foreground\" aria-hidden=\"true\" />\n      Continue with Google\n    </Button>\n  );\n}\n\nfunction PrimaryAction({\n  children,\n  className,\n  onClick,\n}: {\n  children: React.ReactNode;\n  className?: string;\n  onClick: () => void;\n}) {\n  return (\n    <Button\n      type=\"button\"\n      className={cn(\n        \"h-9 w-full rounded-md bg-foreground text-sm font-semibold text-background shadow-none hover:bg-foreground/90 focus-visible:ring-ring\",\n        className\n      )}\n      onClick={onClick}\n    >\n      {children}\n      <ArrowRight data-icon=\"inline-end\" />\n    </Button>\n  );\n}\n\nfunction LargeOptionButton({\n  active,\n  icon: Icon,\n  title,\n  description,\n  onClick,\n}: {\n  active: boolean;\n  icon: LucideIcon;\n  title: string;\n  description: string;\n  onClick: () => void;\n}) {\n  return (\n    <button\n      type=\"button\"\n      className={cn(\n        \"flex min-h-20 w-full items-center gap-4 rounded-lg border border-border bg-background px-5 text-left transition-colors hover:bg-muted/60\",\n        active && \"border-foreground bg-muted/30 ring-2 ring-foreground/10\"\n      )}\n      onClick={onClick}\n    >\n      <Icon className=\"size-7 shrink-0 text-foreground\" />\n      <span className=\"min-w-0\">\n        <span className=\"block text-sm font-semibold text-foreground\">\n          {title}\n        </span>\n        <span className=\"mt-1 block text-sm leading-5 text-muted-foreground\">\n          {description}\n        </span>\n      </span>\n    </button>\n  );\n}\n\nfunction TileOptionButton({\n  active,\n  icon: Icon,\n  title,\n  description,\n  onClick,\n}: {\n  active: boolean;\n  icon: LucideIcon;\n  title: string;\n  description: string;\n  onClick: () => void;\n}) {\n  return (\n    <button\n      type=\"button\"\n      className={cn(\n        \"flex min-h-36 flex-col items-center justify-center rounded-lg border border-border bg-background p-5 text-center transition-colors hover:bg-muted/60\",\n        active && \"border-foreground bg-muted/30 ring-2 ring-foreground/10\"\n      )}\n      onClick={onClick}\n    >\n      <Icon className=\"mb-4 size-8 text-foreground\" />\n      <span className=\"text-sm font-semibold text-foreground\">{title}</span>\n      <span className=\"mt-2 max-w-40 text-xs leading-5 text-muted-foreground\">\n        {description}\n      </span>\n    </button>\n  );\n}\n\nfunction InterestChip({\n  option,\n  active,\n  onClick,\n}: {\n  option: (typeof interestOptions)[number];\n  active: boolean;\n  onClick: () => void;\n}) {\n  const Icon = option.icon;\n\n  return (\n    <button\n      type=\"button\"\n      className={cn(\n        \"inline-flex h-9 items-center gap-2 rounded-lg border border-border bg-background px-3.5 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted/60\",\n        active && \"border-foreground text-foreground ring-2 ring-foreground/10\"\n      )}\n      onClick={onClick}\n    >\n      {active ? <Check className=\"size-4\" /> : <Icon className=\"size-4\" />}\n      {option.label}\n    </button>\n  );\n}\n\nfunction ChecklistRow({ checked, text }: { checked?: boolean; text: string }) {\n  return (\n    <div className=\"flex items-center gap-3\">\n      <span\n        className={cn(\n          \"grid size-5 shrink-0 place-items-center border border-border\",\n          checked && \"border-foreground bg-foreground text-background\"\n        )}\n      >\n        {checked ? <Check className=\"size-4\" /> : null}\n      </span>\n      <span className={cn(checked && \"text-muted-foreground\")}>\n        {text}\n      </span>\n    </div>\n  );\n}\n\nfunction validateCurrentStep(\n  step: OnboardingStep,\n  form: ReturnType<typeof useForm<IntentOnboardingValues>>\n) {\n  const values = form.getValues();\n  const schema = getStepSchema(step);\n\n  form.clearErrors(stepFields[step]);\n\n  if (!schema) {\n    return true;\n  }\n\n  const result = schema.safeParse(values);\n\n  if (result.success) {\n    return true;\n  }\n\n  result.error.issues.forEach((issue) => {\n    const field = issue.path[0] as FieldPath<IntentOnboardingValues>;\n\n    form.setError(field, { message: issue.message, type: \"manual\" });\n  });\n\n  const firstIssue = result.error.issues[0];\n\n  if (firstIssue) {\n    const firstField = firstIssue.path[0] as FieldPath<IntentOnboardingValues>;\n\n    form.setFocus(firstField);\n  }\n\n  return false;\n}\n\nfunction getStepSchema(step: OnboardingStep) {\n  if (step === \"account\") return emailStepSchema;\n  if (step === \"verify\") return verificationStepSchema;\n  if (step === \"profile\") return profileStepSchema;\n  if (step === \"intent\") return intentStepSchema;\n  if (step === \"collaboration\") return collaborationStepSchema;\n\n  return undefined;\n}\n\nfunction getVisibleSteps(values: IntentOnboardingValues) {\n  return onboardingStepValues.filter((step) => !isStepSkipped(step, values));\n}\n\nfunction getVisibleStepIndex(step: OnboardingStep, values: IntentOnboardingValues) {\n  const visibleSteps = getVisibleSteps(values);\n  const index = visibleSteps.indexOf(step);\n\n  return index === -1 ? 0 : index;\n}\n\nfunction getNextStep(step: OnboardingStep, values: IntentOnboardingValues) {\n  const visibleSteps = getVisibleSteps(values);\n  const currentIndex = visibleSteps.indexOf(step);\n\n  return visibleSteps[currentIndex + 1];\n}\n\nfunction isStepSkipped(step: OnboardingStep, values: IntentOnboardingValues) {\n  return step === \"collaboration\" && values.intent !== \"personal\";\n}\n\nfunction getInitials(value: string) {\n  const normalized = value.trim();\n\n  if (!normalized) {\n    return \"A\";\n  }\n\n  return normalized\n    .split(/[\\s@.]+/)\n    .filter(Boolean)\n    .slice(0, 2)\n    .map((part) => part[0]?.toUpperCase())\n    .join(\"\");\n}\n\nfunction getIntentLabel(intent: IntentValue) {\n  return intentOptions.find((option) => option.value === intent)?.title ?? intent;\n}\n\nfunction getIntentSummary(values: IntentOnboardingValues) {\n  if (!values.intent) {\n    return \"Intent captured\";\n  }\n\n  const label = getIntentLabel(values.intent).replace(/^For /, \"\");\n\n  return `Intent set for ${label.toLowerCase()}`;\n}\n\nexport { StepperIntentOnboardingExample };\n",
      "type": "registry:component",
      "target": "@components/stepper-intent-onboarding.tsx"
    },
    {
      "path": "registry/default/components/stepper-logo.tsx",
      "content": "import type { SVGProps } from \"react\";\n\nfunction StepperLogo(props: SVGProps<SVGSVGElement>) {\n  return (\n    <svg\n      viewBox=\"0 0 789.79 1058.83\"\n      fill=\"currentColor\"\n      aria-hidden=\"true\"\n      focusable=\"false\"\n      {...props}\n    >\n      <path d=\"M361.13,1058.28c28.61-24.08,55.58-46.86,82.62-69.55,41.82-35.09,83.8-69.99,125.49-105.23,39.2-33.13,57.7-75.81,57.69-126.9-.05-177.51-.02-355.01-.02-532.52v-9.26c10,3.28,18.99,5.96,27.69,9.36,1.36.53,1.99,4.36,2.02,6.68.17,14.17.25,28.35-.05,42.51-.11,5.26,1.68,7.95,6.82,9.47,15.55,4.58,30.97,9.59,47.4,14.73.21-2.91.48-5.06.49-7.22.1-14.17.02-28.35.23-42.52.15-10.07,3.69-12.79,13.08-9.76,17.45,5.63,34.83,11.45,52.15,17.48,9.32,3.24,12.66,8.43,12.67,18.46.03,35.78-.07,71.56.05,107.34.03,7.56-2.6,13.42-8.55,18.1-9.31,7.32-18.32,15.04-27.71,22.25-3.47,2.67-4.92,5.42-4.91,9.88.11,138.01.03,276.02.1,414.03.01,32.23-2.08,64.19-14.18,94.47-24.52,61.33-67.45,101.93-133.21,115.85-9.24,1.96-18.91,2.61-28.38,2.64-67.61.24-135.22.17-202.83.18-2.22,0-4.44-.24-8.67-.49ZM707.67,578.13c0-28.19.75-55.54-.53-82.79-.32-6.88-5.92-14.7-11.24-19.89-10.81-10.58-24.41-6.66-29.84,7.52-1.06,2.78-1.94,5.84-1.96,8.77-.15,24.56-.09,49.13-.09,74.2,14.53,4.06,28.94,8.09,43.64,12.2Z\" />\n      <path d=\"M550.29,611.15h-140.74c-.15-3.18-.37-5.67-.37-8.15-.02-58.79.02-117.58-.07-176.37,0-4.36.43-7.09,5.61-8.45,58.86-15.42,117.64-31.12,176.45-46.74.42-.11.9-.01,2.63-.01,0,2.81,0,5.68,0,8.54-.03,125.94.18,251.88-.23,377.83-.13,40.79-16.04,74.87-47.7,101.19-78.26,65.05-156.45,130.16-234.85,195.04-3.21,2.66-8.17,4.4-12.36,4.49-21.32.45-42.66.21-66.02.21,3.09-2.75,4.81-4.38,6.64-5.88,71.94-58.84,143.89-117.65,215.82-176.5,19.42-15.89,38.64-32.02,58.12-47.83,25.37-20.58,37.33-47.15,37.14-79.7-.26-43.22-.07-86.44-.08-129.66,0-2.29,0-4.57,0-8Z\" />\n      <path d=\"M560.11,210.07c0-7.96,0-15.13,0-22.31.01-55.3.02-110.61.03-165.91,0-13.02,7.86-22.02,19.1-21.85,11.18.17,18.62,8.67,18.62,21.58-.02,58.79,3.25,117.83-1.19,176.29-3.69,48.59-.74,96.93-2.82,145.33-.24,5.6-3.85,5.64-7.21,6.51-38.68,10.01-77.36,19.98-116.08,29.85-26.11,6.66-52.25,13.21-78.42,19.65-13.71,3.38-24.86-5.34-24.87-19.28-.03-34.86.01-69.71.07-104.57.02-12.2,5.31-18.61,17.17-21.91,16.55-4.6,33.02-9.5,49.53-14.27,12.34-3.56,18.24.81,18.31,13.64.07,11.85-.05,23.7.09,35.55.09,7.1,1.61,8.22,8.64,6.39,14.15-3.7,28.21-7.77,42.4-11.3,5.37-1.34,6.93-4.22,6.84-9.43-.26-14.4.02-28.81-.19-43.22-.1-6.94,2.65-10.63,9.69-11.98,13.22-2.53,26.31-5.68,40.3-8.76Z\" />\n      <path d=\"M361.32,924.39c-47.66,5.68-95.31,11.36-143.75,17.13-.12,2.35-.34,4.79-.35,7.24-.04,23.47.13,46.94-.25,70.41-.05,3.11-2.01,7.08-4.39,9.12-10.77,9.2-21.85,18.06-33.17,26.57-2.88,2.16-7.06,3.65-10.65,3.67-49.49.29-98.99.3-148.49.31-13.39,0-20.24-6.84-20.25-20.15-.04-31.6-.03-63.21.03-94.81.03-13.68,7.96-21.79,21.61-21.78,95.97.05,191.94.2,287.91.31,17.15.02,34.3,0,51.45,0,.1.66.2,1.33.3,1.99Z\" />\n      <path d=\"M179.64,881.76c0-27.43-.27-54.36.13-81.28.16-11.16,9.64-18.62,21.94-18.62,52.72.02,105.44.02,158.16.07,44.36.04,88.72.15,133.07.23,3.93,0,7.87,0,11.94,1.58-41.18,4.92-82.37,9.83-124.17,14.82v83.19h-201.07Z\" />\n      <path d=\"M541.46,651.31v11.92h-63.14v83.22h-180.91c-.16-2.11-.45-4.12-.45-6.13-.03-21.82-.06-43.65.02-65.47.05-15.26,8.51-23.64,23.77-23.63,70.81.02,141.62.06,212.43.1,2.51,0,5.02,0,8.29,0Z\" />\n      <path d=\"M789.79,68.43c-21.66,23.89-42.73,46.06-74.45,52.96-7.27,1.58-15.63,2.2-22.63.21-25.49-7.24-50.59-9.24-76.16,1.67-.36-2.34-.77-3.82-.79-5.3-.28-22.74-.36-45.48-.88-68.22-.11-4.86,1.6-6.76,6.03-8.28,34.87-11.94,67.86-10,98.71,11.86,19.17,13.58,40.53,19.02,63.96,15.43,1.5-.23,3.04-.17,6.2-.33Z\" />\n      <path d=\"M230.89,504.03c27.49.25,49.21,22.49,48.96,50.14-.27,28.73-22.72,51.45-50.58,51.18-27.41-.27-49.86-23.56-49.59-51.46.26-27.63,23.35-50.1,51.22-49.85Z\" />\n    </svg>\n  );\n}\n\nexport { StepperLogo };\n",
      "type": "registry:component",
      "target": "@components/stepper-logo.tsx"
    }
  ],
  "type": "registry:block"
}