{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "magic-link",
  "title": "Magic Link",
  "description": "Magic-link plugin: passwordless email sign-in form, toggle button between password and magic-link routes, and the AuthPlugin scaffolding that registers the view with `<Auth>`.",
  "dependencies": [
    "@better-auth-ui/react@latest",
    "@better-auth-ui/core@latest",
    "better-auth",
    "lucide-react"
  ],
  "registryDependencies": [
    "badge",
    "button",
    "card",
    "input",
    "field",
    "separator",
    "sonner",
    "spinner",
    "tooltip"
  ],
  "files": [
    {
      "path": "src/lib/auth/auth-plugin.ts",
      "content": "import type {\n  AuthPluginComponents,\n  AuthPlugin as AuthPluginPrimitive\n} from \"@better-auth-ui/react\"\n\ndeclare module \"@better-auth-ui/core\" {\n  /** Widens `useAuth().plugins` to the shadcn-typed `AuthPlugin`. */\n  interface AuthPluginRegister {\n    shadcn: AuthPlugin\n  }\n}\n\n/** Props the shadcn `<Auth>` router spreads onto plugin-contributed auth views. */\nexport type AuthViewProps = {\n  className?: string\n  socialLayout?: \"auto\" | \"horizontal\" | \"vertical\" | \"grid\"\n  socialPosition?: \"top\" | \"bottom\"\n}\n\n/** Props the shadcn `<Settings>` router spreads onto plugin-contributed settings views. */\nexport type SettingsViewProps = {\n  className?: string\n}\n\n/** Shadcn plugin type. Plugin authors import this from `@/lib/auth/auth-plugin`. */\nexport type AuthPlugin = AuthPluginPrimitive<\n  AuthPluginComponents,\n  AuthViewProps,\n  SettingsViewProps\n>\n",
      "type": "registry:lib",
      "target": "@lib/auth/auth-plugin.ts"
    },
    {
      "path": "src/lib/auth/magic-link-plugin.ts",
      "content": "import { createAuthPlugin } from \"@better-auth-ui/core\"\nimport {\n  magicLinkPlugin as coreMagicLinkPlugin,\n  type MagicLinkPluginOptions\n} from \"@better-auth-ui/core/plugins\"\n\nimport { MagicLink } from \"@/components/auth/magic-link\"\nimport { MagicLinkButton } from \"@/components/auth/magic-link-button\"\nimport { MagicLinkSent } from \"@/components/auth/magic-link-sent\"\n\nexport const magicLinkPlugin = createAuthPlugin(\n  coreMagicLinkPlugin.id,\n  (options: MagicLinkPluginOptions = {}) => ({\n    ...coreMagicLinkPlugin(options),\n    authButtons: [MagicLinkButton],\n    views: {\n      auth: { magicLink: MagicLink, magicLinkSent: MagicLinkSent }\n    },\n    // Conditional, not an override: when `emailAndPassword.enabled === false`\n    // the `<Auth>` router renders this at `/auth/sign-in` instead of the\n    // disabled password form. With password auth on, the built-in `SignIn`\n    // still wins.\n    fallbackViews: {\n      auth: { signIn: MagicLink }\n    }\n  })\n)\n",
      "type": "registry:lib",
      "target": "@lib/auth/magic-link-plugin.ts"
    },
    {
      "path": "src/components/auth/magic-link.tsx",
      "content": "\"use client\"\n\nimport { authMutationKeys } from \"@better-auth-ui/core\"\nimport {\n  type MagicLinkAuthClient,\n  useAuth,\n  useAuthPlugin,\n  useSignInMagicLink\n} from \"@better-auth-ui/react\"\nimport { useIsMutating } from \"@tanstack/react-query\"\nimport { type SyntheticEvent, useState } from \"react\"\n\nimport { Button } from \"@/components/ui/button\"\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\"\nimport {\n  Field,\n  FieldDescription,\n  FieldError,\n  FieldGroup,\n  FieldLabel,\n  FieldSeparator\n} from \"@/components/ui/field\"\nimport { Input } from \"@/components/ui/input\"\nimport { Spinner } from \"@/components/ui/spinner\"\nimport { magicLinkPlugin } from \"@/lib/auth/magic-link-plugin\"\nimport { cn } from \"@/lib/utils\"\nimport { MAGIC_LINK_SENT_STORAGE_KEY } from \"./magic-link-sent\"\nimport { ProviderButtons, type SocialLayout } from \"./provider-buttons\"\n\nexport type MagicLinkProps = {\n  className?: string\n  socialLayout?: SocialLayout\n  socialPosition?: \"top\" | \"bottom\"\n}\n\n/**\n * Render a card-based sign-in form that sends an email magic link and optionally shows social provider buttons.\n *\n * @param className - Additional CSS class names applied to the card container\n * @param socialLayout - Layout style for social provider buttons\n * @param socialPosition - Position of social provider buttons; `\"top\"` or `\"bottom\"`. Defaults to `\"bottom\"`.\n * @returns The magic-link sign-in UI as a JSX element\n */\nexport function MagicLink({\n  className,\n  socialLayout,\n  socialPosition = \"bottom\"\n}: MagicLinkProps) {\n  const {\n    authClient,\n    basePaths,\n    baseURL,\n    emailAndPassword,\n    localization,\n    navigate,\n    plugins,\n    redirectTo,\n    socialProviders,\n    viewPaths,\n    Link\n  } = useAuth()\n  const { localization: magicLinkLocalization, viewPaths: magicLinkViewPaths } =\n    useAuthPlugin(magicLinkPlugin)\n\n  const [email, setEmail] = useState(\"\")\n\n  const { mutate: signInMagicLink, isPending: signInMagicLinkPending } =\n    useSignInMagicLink(authClient as MagicLinkAuthClient, {\n      onSuccess: (_data, variables) => {\n        sessionStorage.setItem(MAGIC_LINK_SENT_STORAGE_KEY, variables.email)\n        navigate({\n          to: `${basePaths.auth}/${magicLinkViewPaths.auth.magicLinkSent}`\n        })\n      }\n    })\n\n  const signInMutating = useIsMutating({\n    mutationKey: authMutationKeys.signIn.all\n  })\n  const signUpMutating = useIsMutating({\n    mutationKey: authMutationKeys.signUp.all\n  })\n  const isPending = signInMutating + signUpMutating > 0\n\n  const [fieldErrors, setFieldErrors] = useState<{\n    email?: string\n  }>({})\n\n  const handleSubmit = (e: SyntheticEvent<HTMLFormElement>) => {\n    e.preventDefault()\n    signInMagicLink({ email, callbackURL: `${baseURL}${redirectTo}` })\n  }\n\n  const showSeparator = socialProviders && socialProviders.length > 0\n\n  return (\n    <Card className={cn(\"w-full max-w-sm\", className)}>\n      <CardHeader>\n        <CardTitle className=\"text-xl\">{localization.auth.signIn}</CardTitle>\n      </CardHeader>\n\n      <CardContent>\n        <div className=\"flex flex-col gap-6\">\n          {socialPosition === \"top\" && (\n            <>\n              {socialProviders && socialProviders.length > 0 && (\n                <ProviderButtons socialLayout={socialLayout} view=\"magicLink\" />\n              )}\n\n              {showSeparator && (\n                <FieldSeparator className=\"*:data-[slot=field-separator-content]:bg-card m-0 text-xs flex items-center\">\n                  {localization.auth.or}\n                </FieldSeparator>\n              )}\n            </>\n          )}\n\n          <form onSubmit={handleSubmit}>\n            <FieldGroup>\n              <Field data-invalid={!!fieldErrors.email}>\n                <FieldLabel htmlFor=\"email\">\n                  {localization.auth.email}\n                </FieldLabel>\n\n                <Input\n                  id=\"email\"\n                  name=\"email\"\n                  type=\"email\"\n                  autoComplete=\"email\"\n                  value={email}\n                  onChange={(e) => {\n                    setEmail(e.target.value)\n\n                    setFieldErrors((prev) => ({\n                      ...prev,\n                      email: undefined\n                    }))\n                  }}\n                  placeholder={localization.auth.emailPlaceholder}\n                  required\n                  disabled={isPending}\n                  onInvalid={(e) => {\n                    e.preventDefault()\n\n                    setFieldErrors((prev) => ({\n                      ...prev,\n                      email: (e.target as HTMLInputElement).validationMessage\n                    }))\n                  }}\n                  aria-invalid={!!fieldErrors.email}\n                />\n\n                <FieldError>{fieldErrors.email}</FieldError>\n              </Field>\n\n              <div className=\"flex flex-col gap-3\">\n                <Button type=\"submit\" disabled={isPending}>\n                  {signInMagicLinkPending && <Spinner />}\n\n                  {magicLinkLocalization.sendMagicLink}\n                </Button>\n\n                {plugins.flatMap((plugin) =>\n                  (plugin.authButtons ?? []).map((AuthButton, index) => (\n                    <AuthButton\n                      key={`${plugin.id}-${index.toString()}`}\n                      view=\"magicLink\"\n                    />\n                  ))\n                )}\n              </div>\n            </FieldGroup>\n          </form>\n\n          {socialPosition === \"bottom\" && (\n            <>\n              {showSeparator && (\n                <FieldSeparator className=\"*:data-[slot=field-separator-content]:bg-card text-xs flex items-center\">\n                  {localization.auth.or}\n                </FieldSeparator>\n              )}\n\n              {socialProviders && socialProviders.length > 0 && (\n                <ProviderButtons socialLayout={socialLayout} view=\"magicLink\" />\n              )}\n            </>\n          )}\n        </div>\n\n        {emailAndPassword?.enabled && (\n          <div className=\"flex flex-col gap-3 items-center w-full mt-4\">\n            <FieldDescription className=\"text-center\">\n              {localization.auth.needToCreateAnAccount}{\" \"}\n              <Link\n                href={`${basePaths.auth}/${viewPaths.auth.signUp}`}\n                className=\"underline underline-offset-4\"\n              >\n                {localization.auth.signUp}\n              </Link>\n            </FieldDescription>\n          </div>\n        )}\n      </CardContent>\n    </Card>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/magic-link.tsx"
    },
    {
      "path": "src/components/auth/magic-link-sent.tsx",
      "content": "\"use client\"\n\nimport { useAuth, useAuthPlugin } from \"@better-auth-ui/react\"\nimport { useEffect, useState } from \"react\"\n\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\"\nimport { FieldDescription } from \"@/components/ui/field\"\nimport { magicLinkPlugin } from \"@/lib/auth/magic-link-plugin\"\nimport { cn } from \"@/lib/utils\"\nimport { OpenEmailButton } from \"./open-email-button\"\nimport { useIsHydrated } from \"./use-is-hydrated\"\n\n/** `sessionStorage` key the magic-link form stores the submitted email under. */\nexport const MAGIC_LINK_SENT_STORAGE_KEY = \"better-auth-ui.magic-link-sent\"\n\nexport type MagicLinkSentProps = {\n  className?: string\n}\n\n/**\n * Render a card confirming that a magic-link email was sent, with a button\n * to open the user's email provider.\n *\n * The target email is read from `sessionStorage` (set when the magic-link\n * form redirects here); the OpenEmail button is only shown when an email is\n * stored and resolves to a known provider.\n *\n * @param className - Additional CSS classes applied to the card\n * @returns The magic-link-sent card React element\n */\nexport function MagicLinkSent({ className }: MagicLinkSentProps) {\n  const { basePaths, emailAndPassword, localization, viewPaths, Link } =\n    useAuth()\n  const { localization: magicLinkLocalization } = useAuthPlugin(magicLinkPlugin)\n\n  const isHydrated = useIsHydrated()\n  const [email, setEmail] = useState(\n    (isHydrated && sessionStorage.getItem(MAGIC_LINK_SENT_STORAGE_KEY)) || \"\"\n  )\n\n  useEffect(() => {\n    setEmail(sessionStorage.getItem(MAGIC_LINK_SENT_STORAGE_KEY) ?? \"\")\n  }, [])\n\n  return (\n    <Card className={cn(\"w-full max-w-sm\", className)}>\n      <CardHeader>\n        <CardTitle className=\"text-xl font-semibold\">\n          {localization.auth.checkYourEmailTitle}\n        </CardTitle>\n      </CardHeader>\n\n      <CardContent>\n        <div className=\"flex flex-col gap-4\">\n          <FieldDescription>\n            {email\n              ? magicLinkLocalization.magicLinkSentTo.replace(\n                  \"{{email}}\",\n                  email\n                )\n              : magicLinkLocalization.magicLinkSent}\n          </FieldDescription>\n\n          {email && <OpenEmailButton email={email} />}\n        </div>\n\n        {emailAndPassword?.enabled && (\n          <div className=\"flex flex-col gap-3 items-center w-full mt-4\">\n            <FieldDescription className=\"text-center\">\n              {localization.auth.needToCreateAnAccount}{\" \"}\n              <Link\n                href={`${basePaths.auth}/${viewPaths.auth.signUp}`}\n                className=\"underline underline-offset-4\"\n              >\n                {localization.auth.signUp}\n              </Link>\n            </FieldDescription>\n          </div>\n        )}\n      </CardContent>\n    </Card>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/magic-link-sent.tsx"
    },
    {
      "path": "src/components/auth/magic-link-button.tsx",
      "content": "\"use client\"\n\nimport { type AuthView, authMutationKeys } from \"@better-auth-ui/core\"\nimport { useAuth, useAuthPlugin } from \"@better-auth-ui/react\"\nimport { useIsMutating } from \"@tanstack/react-query\"\nimport { Lock, Mail } from \"lucide-react\"\n\nimport { buttonVariants } from \"@/components/ui/button\"\nimport { magicLinkPlugin } from \"@/lib/auth/magic-link-plugin\"\nimport { cn } from \"@/lib/utils\"\n\nexport type MagicLinkButtonProps = {\n  /** @remarks `AuthView` */\n  view?: AuthView\n}\n\n/**\n * Toggle button between the password sign-in and magic-link routes.\n *\n * @param view - Current auth view. On `\"magicLink\"` this links back to password sign-in.\n */\nexport function MagicLinkButton({ view }: MagicLinkButtonProps) {\n  const { basePaths, emailAndPassword, viewPaths, localization, Link } =\n    useAuth()\n\n  const signInMutating = useIsMutating({\n    mutationKey: authMutationKeys.signIn.all\n  })\n  const signUpMutating = useIsMutating({\n    mutationKey: authMutationKeys.signUp.all\n  })\n  const isPending = signInMutating + signUpMutating > 0\n\n  const { localization: magicLinkLocalization, viewPaths: magicLinkViewPaths } =\n    useAuthPlugin(magicLinkPlugin)\n\n  const isMagicLinkView = view === \"magicLink\"\n\n  // On the magic-link view this button switches back to password sign-in.\n  // With password auth disabled there's nowhere to switch to, so hide it.\n  // (Other views — e.g. a phone-number plugin's surface — still get a\n  // \"Continue with Magic Link\" link.)\n  if (isMagicLinkView && !emailAndPassword?.enabled) return null\n\n  return (\n    <Link\n      href={`${basePaths.auth}/${isMagicLinkView ? viewPaths.auth.signIn : magicLinkViewPaths.auth.magicLink}`}\n      aria-disabled={isPending || undefined}\n      tabIndex={isPending ? -1 : undefined}\n      onClick={(event) => {\n        if (isPending) event.preventDefault()\n      }}\n      className={cn(\n        buttonVariants({ variant: \"outline\" }),\n        \"w-full\",\n        isPending && \"opacity-50 pointer-events-none\"\n      )}\n    >\n      {isMagicLinkView ? <Lock /> : <Mail />}\n\n      {localization.auth.continueWith.replace(\n        \"{{provider}}\",\n        isMagicLinkView\n          ? localization.auth.password\n          : magicLinkLocalization.magicLink\n      )}\n    </Link>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/magic-link-button.tsx"
    },
    {
      "path": "src/components/auth/provider-button.tsx",
      "content": "\"use client\"\n\nimport {\n  type AuthView,\n  authMutationKeys,\n  getProviderName\n} from \"@better-auth-ui/core\"\nimport { providerIcons, useAuth, useSignInSocial } from \"@better-auth-ui/react\"\nimport { useIsMutating } from \"@tanstack/react-query\"\nimport type { SocialProvider } from \"better-auth/social-providers\"\nimport type { ComponentProps } from \"react\"\n\nimport { Button } from \"@/components/ui/button\"\nimport { Spinner } from \"@/components/ui/spinner\"\nimport { cn } from \"@/lib/utils\"\nimport { LastUsedBadge } from \"./last-login-method/last-used-badge\"\n\nexport type ProviderButtonProps = {\n  provider: SocialProvider\n  display?: \"full\" | \"name\" | \"icon\"\n  view?: AuthView\n} & Omit<ComponentProps<typeof Button>, \"onClick\" | \"children\" | \"disabled\">\n\n/**\n * Social provider sign-in button.\n *\n * @param provider - Provider to sign in with.\n * @param display - `\"full\"` (e.g. \"Continue with Google\"), `\"name\"` (just the provider name), or `\"icon\"` (icon only).\n */\nexport function ProviderButton({\n  provider,\n  display = \"full\",\n  view = \"signIn\",\n  variant = \"outline\",\n  className,\n  ...props\n}: ProviderButtonProps) {\n  const { authClient, baseURL, localization, redirectTo } = useAuth()\n\n  const callbackURL = `${baseURL}${redirectTo}`\n\n  const { mutate: signInSocial, isPending: signInSocialPending } =\n    useSignInSocial(authClient)\n\n  const ProviderIcon = providerIcons[provider]\n\n  const signInMutating = useIsMutating({\n    mutationKey: authMutationKeys.signIn.all\n  })\n  const signUpMutating = useIsMutating({\n    mutationKey: authMutationKeys.signUp.all\n  })\n  const isPending = signInMutating + signUpMutating > 0\n\n  return (\n    <Button\n      type=\"button\"\n      variant={variant}\n      disabled={isPending}\n      onClick={() => signInSocial({ provider, callbackURL })}\n      className={cn(\"relative overflow-visible\", className)}\n      {...props}\n    >\n      {signInSocialPending ? (\n        <Spinner />\n      ) : ProviderIcon ? (\n        <ProviderIcon />\n      ) : null}\n\n      {display === \"full\"\n        ? localization.auth.continueWith.replace(\n            \"{{provider}}\",\n            getProviderName(provider)\n          )\n        : display === \"name\"\n          ? getProviderName(provider)\n          : null}\n\n      {display === \"icon\" && (\n        <span className=\"sr-only\">{getProviderName(provider)}</span>\n      )}\n\n      {view !== \"signUp\" && <LastUsedBadge method={provider} floating />}\n    </Button>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/provider-button.tsx"
    },
    {
      "path": "src/components/auth/provider-buttons.tsx",
      "content": "\"use client\"\n\nimport type { AuthView } from \"@better-auth-ui/core\"\nimport { useAuth } from \"@better-auth-ui/react\"\nimport { useMemo } from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ProviderButton } from \"./provider-button\"\n\nexport type ProviderButtonsProps = {\n  socialLayout?: SocialLayout\n  view?: AuthView\n}\n\nexport type SocialLayout = \"auto\" | \"horizontal\" | \"vertical\" | \"grid\"\n\n/**\n * Render sign-in buttons for configured social providers. Each button owns its own sign-in mutation\n * and reads the shared sign-in pending state from React Query.\n *\n * @param socialLayout - Preferred layout for the provider buttons; `\"auto\"` chooses based on the number of providers.\n */\nexport function ProviderButtons({\n  socialLayout = \"auto\",\n  view = \"signIn\"\n}: ProviderButtonsProps) {\n  const { socialProviders } = useAuth()\n\n  const resolvedSocialLayout = useMemo(() => {\n    if (socialLayout === \"auto\") {\n      if (socialProviders?.length && socialProviders.length >= 4) {\n        return \"horizontal\"\n      }\n\n      return \"vertical\"\n    }\n\n    return socialLayout\n  }, [socialLayout, socialProviders?.length])\n\n  return (\n    <div\n      className={cn(\n        \"gap-3\",\n        resolvedSocialLayout === \"grid\" && \"grid grid-cols-2\",\n        resolvedSocialLayout === \"vertical\" && \"flex flex-col\",\n        resolvedSocialLayout === \"horizontal\" && \"flex flex-row flex-wrap\"\n      )}\n    >\n      {socialProviders?.map((provider) => (\n        <ProviderButton\n          key={provider}\n          provider={provider}\n          view={view}\n          display={\n            resolvedSocialLayout === \"vertical\"\n              ? \"full\"\n              : resolvedSocialLayout === \"grid\"\n                ? \"name\"\n                : \"icon\"\n          }\n          className={cn(resolvedSocialLayout === \"horizontal\" && \"flex-1\")}\n        />\n      ))}\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/provider-buttons.tsx"
    },
    {
      "path": "src/components/auth/open-email-button.tsx",
      "content": "\"use client\"\n\nimport { createQrCodeSvgData, getEmailProviderLink } from \"@better-auth-ui/core\"\nimport { useAuth } from \"@better-auth-ui/react\"\nimport type { VariantProps } from \"class-variance-authority\"\nimport { QrCode } from \"lucide-react\"\nimport { useMemo } from \"react\"\n\nimport { buttonVariants } from \"@/components/ui/button\"\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger\n} from \"@/components/ui/tooltip\"\nimport { cn } from \"@/lib/utils\"\n\nexport type OpenEmailButtonProps = {\n  /** Email address used to detect the provider, e.g. from the verify-email flow. */\n  email: string\n  className?: string\n  /**\n   * Button variant. Defaults to the primary style for dead-end views where\n   * opening the inbox is the only action; pass `\"secondary\"` where it sits\n   * beside a submit button that should stay the primary call to action.\n   */\n  variant?: VariantProps<typeof buttonVariants>[\"variant\"]\n}\n\n/**\n * Render a button that opens the user's email provider login page in a new\n * tab. Hovering or focusing the button reveals a QR code for opening the same\n * provider on another device.\n *\n * The provider is resolved from the email domain via the curated\n * `@mikkelscheike/email-provider-links` dataset (Gmail, Outlook, GMX, etc.).\n * Renders nothing when the domain is empty or not a known provider.\n *\n * @param email - Email address to resolve the provider from.\n * @param className - Additional CSS classes applied to the button.\n * @param variant - Button variant. Defaults to the primary style.\n * @returns The open-email button, or `null` when no provider matches.\n */\nexport function OpenEmailButton({\n  email,\n  className,\n  variant\n}: OpenEmailButtonProps) {\n  const { localization } = useAuth()\n\n  const provider = getEmailProviderLink(email)\n  const loginUrl = provider?.loginUrl\n  const qrCode = useMemo(\n    () => (loginUrl ? createQrCodeSvgData(loginUrl) : null),\n    [loginUrl]\n  )\n\n  if (!provider || !qrCode) return null\n\n  const scanLabel = localization.auth.scanToOpenEmailProvider.replace(\n    \"{{provider}}\",\n    provider.companyProvider\n  )\n\n  return (\n    <TooltipProvider>\n      <Tooltip>\n        <TooltipTrigger\n          type=\"button\"\n          className={cn(buttonVariants({ variant }), \"w-full\", className)}\n          onClick={() =>\n            window.open(provider.loginUrl, \"_blank\", \"noopener,noreferrer\")\n          }\n        >\n          {localization.auth.openEmailProvider.replace(\n            \"{{provider}}\",\n            provider.companyProvider\n          )}\n          <QrCode data-icon=\"inline-end\" />\n        </TooltipTrigger>\n        <TooltipContent\n          sideOffset={8}\n          className=\"flex-col items-center gap-2 p-3\"\n        >\n          <svg\n            viewBox={`0 0 ${qrCode.size} ${qrCode.size}`}\n            aria-hidden=\"true\"\n            focusable=\"false\"\n            className=\"size-40\"\n          >\n            <path fill=\"white\" d={`M0 0h${qrCode.size}v${qrCode.size}H0z`} />\n            <path fill=\"black\" d={qrCode.path} shapeRendering=\"crispEdges\" />\n          </svg>\n          <p className=\"max-w-40 text-center leading-snug\">{scanLabel}</p>\n        </TooltipContent>\n      </Tooltip>\n    </TooltipProvider>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/open-email-button.tsx"
    },
    {
      "path": "src/components/auth/use-is-hydrated.ts",
      "content": "\"use client\"\n\nimport { useSyncExternalStore } from \"react\"\n\n/**\n * Returns `true` once the component is mounted on the client (hydrated) and\n * `false` while rendering on the server, so client-only reads (e.g.\n * `sessionStorage`) stay safe during SSR.\n *\n * @returns Whether the component has hydrated on the client.\n */\nexport function useIsHydrated() {\n  const subscribe = () => () => {}\n  return useSyncExternalStore(\n    subscribe,\n    () => true,\n    () => false\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/use-is-hydrated.ts"
    },
    {
      "path": "src/components/auth/last-login-method/last-used-badge.tsx",
      "content": "\"use client\"\n\nimport { useLastLoginMethod } from \"@better-auth-ui/react\"\n\nimport { Badge } from \"@/components/ui/badge\"\n\nexport type LastUsedBadgeProps = {\n  /** Login method IDs that should display the indicator. */\n  method: string | string[]\n  /** Use the shorter label in constrained layouts. */\n  compact?: boolean\n  /** Float the compact indicator over the top-right edge of its container. */\n  floating?: boolean\n}\n\n/**\n * Displays an indicator when one of the supplied method IDs matches Better\n * Auth's stored last login method.\n */\nexport function LastUsedBadge({\n  method,\n  compact,\n  floating\n}: LastUsedBadgeProps) {\n  const { method: lastLoginMethod, localization } = useLastLoginMethod()\n  const methods = Array.isArray(method) ? method : [method]\n\n  if (!lastLoginMethod || !methods.includes(lastLoginMethod)) return null\n\n  return (\n    <Badge\n      className={\n        floating\n          ? \"pointer-events-none absolute top-0 right-0 z-10 translate-x-1/4 -translate-y-1/2 shadow-sm\"\n          : undefined\n      }\n      variant=\"secondary\"\n    >\n      {compact || floating ? localization.lastUsedShort : localization.lastUsed}\n    </Badge>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/last-login-method/last-used-badge.tsx"
    }
  ],
  "type": "registry:component"
}