{"version":3,"file":"useBlocker.cjs","sources":["../../src/useBlocker.tsx"],"sourcesContent":["import * as React from 'react'\nimport { useRouter } from './useRouter'\nimport type {\n  BlockerFnArgs,\n  HistoryAction,\n  HistoryLocation,\n} from '@tanstack/history'\nimport type {\n  AnyRoute,\n  AnyRouter,\n  ParseRoute,\n  RegisteredRouter,\n} from '@tanstack/router-core'\n\ninterface ShouldBlockFnLocation<\n  out TRouteId,\n  out TFullPath,\n  out TAllParams,\n  out TFullSearchSchema,\n> {\n  routeId: TRouteId\n  fullPath: TFullPath\n  pathname: string\n  params: TAllParams\n  search: TFullSearchSchema\n}\n\ntype AnyShouldBlockFnLocation = ShouldBlockFnLocation<any, any, any, any>\ntype MakeShouldBlockFnLocationUnion<\n  TRouter extends AnyRouter = RegisteredRouter,\n  TRoute extends AnyRoute = ParseRoute<TRouter['routeTree']>,\n> = TRoute extends any\n  ? ShouldBlockFnLocation<\n      TRoute['id'],\n      TRoute['fullPath'],\n      TRoute['types']['allParams'],\n      TRoute['types']['fullSearchSchema']\n    >\n  : never\n\ntype BlockerResolver<TRouter extends AnyRouter = RegisteredRouter> =\n  | {\n      status: 'blocked'\n      current: MakeShouldBlockFnLocationUnion<TRouter>\n      next: MakeShouldBlockFnLocationUnion<TRouter>\n      action: HistoryAction\n      proceed: () => void\n      reset: () => void\n    }\n  | {\n      status: 'idle'\n      current: undefined\n      next: undefined\n      action: undefined\n      proceed: undefined\n      reset: undefined\n    }\n\ntype ShouldBlockFnArgs<TRouter extends AnyRouter = RegisteredRouter> = {\n  current: MakeShouldBlockFnLocationUnion<TRouter>\n  next: MakeShouldBlockFnLocationUnion<TRouter>\n  action: HistoryAction\n}\n\nexport type ShouldBlockFn<TRouter extends AnyRouter = RegisteredRouter> = (\n  args: ShouldBlockFnArgs<TRouter>,\n) => boolean | Promise<boolean>\nexport type UseBlockerOpts<\n  TRouter extends AnyRouter = RegisteredRouter,\n  TWithResolver extends boolean = boolean,\n> = {\n  shouldBlockFn: ShouldBlockFn<TRouter>\n  enableBeforeUnload?: boolean | (() => boolean)\n  disabled?: boolean\n  withResolver?: TWithResolver\n}\n\ntype LegacyBlockerFn = () => Promise<any> | any\ntype LegacyBlockerOpts = {\n  blockerFn?: LegacyBlockerFn\n  condition?: boolean | any\n}\n\nfunction _resolveBlockerOpts(\n  opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,\n  condition?: boolean | any,\n): UseBlockerOpts {\n  if (opts === undefined) {\n    return {\n      shouldBlockFn: () => true,\n      withResolver: false,\n    }\n  }\n\n  if ('shouldBlockFn' in opts) {\n    return opts\n  }\n\n  if (typeof opts === 'function') {\n    const shouldBlock = Boolean(condition ?? true)\n\n    const _customBlockerFn = async () => {\n      if (shouldBlock) return await opts()\n      return false\n    }\n\n    return {\n      shouldBlockFn: _customBlockerFn,\n      enableBeforeUnload: shouldBlock,\n      withResolver: false,\n    }\n  }\n\n  const shouldBlock = Boolean(opts.condition ?? true)\n  const fn = opts.blockerFn\n\n  const _customBlockerFn = async () => {\n    if (shouldBlock && fn !== undefined) {\n      return await fn()\n    }\n    return shouldBlock\n  }\n\n  return {\n    shouldBlockFn: _customBlockerFn,\n    enableBeforeUnload: shouldBlock,\n    withResolver: fn === undefined,\n  }\n}\n\nexport function useBlocker<\n  TRouter extends AnyRouter = RegisteredRouter,\n  TWithResolver extends boolean = false,\n>(\n  opts: UseBlockerOpts<TRouter, TWithResolver>,\n): TWithResolver extends true ? BlockerResolver<TRouter> : void\n\n/**\n * @deprecated Use the shouldBlockFn property instead\n */\nexport function useBlocker(blockerFnOrOpts?: LegacyBlockerOpts): BlockerResolver\n\n/**\n * @deprecated Use the UseBlockerOpts object syntax instead\n */\nexport function useBlocker(\n  blockerFn?: LegacyBlockerFn,\n  condition?: boolean | any,\n): BlockerResolver\n\nexport function useBlocker(\n  opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,\n  condition?: boolean | any,\n): BlockerResolver | void {\n  const {\n    shouldBlockFn,\n    enableBeforeUnload = true,\n    disabled = false,\n    withResolver = false,\n  } = _resolveBlockerOpts(opts, condition)\n\n  const router = useRouter()\n  const { history } = router\n\n  const [resolver, setResolver] = React.useState<BlockerResolver>({\n    status: 'idle',\n    current: undefined,\n    next: undefined,\n    action: undefined,\n    proceed: undefined,\n    reset: undefined,\n  })\n\n  React.useEffect(() => {\n    const blockerFnComposed = async (blockerFnArgs: BlockerFnArgs) => {\n      function getLocation(\n        location: HistoryLocation,\n      ): AnyShouldBlockFnLocation {\n        const parsedLocation = router.parseLocation(location)\n        const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname)\n        if (matchedRoutes.foundRoute === undefined) {\n          return {\n            routeId: '__notFound__',\n            fullPath: parsedLocation.pathname,\n            pathname: parsedLocation.pathname,\n            params: matchedRoutes.routeParams,\n            search: router.options.parseSearch(location.search),\n          }\n        }\n\n        return {\n          routeId: matchedRoutes.foundRoute.id,\n          fullPath: matchedRoutes.foundRoute.fullPath,\n          pathname: parsedLocation.pathname,\n          params: matchedRoutes.routeParams,\n          search: router.options.parseSearch(location.search),\n        }\n      }\n\n      const current = getLocation(blockerFnArgs.currentLocation)\n      const next = getLocation(blockerFnArgs.nextLocation)\n\n      if (\n        current.routeId === '__notFound__' &&\n        next.routeId !== '__notFound__'\n      ) {\n        return false\n      }\n\n      const shouldBlock = await shouldBlockFn({\n        action: blockerFnArgs.action,\n        current,\n        next,\n      })\n      if (!withResolver) {\n        return shouldBlock\n      }\n\n      if (!shouldBlock) {\n        return false\n      }\n\n      const promise = new Promise<boolean>((resolve) => {\n        setResolver({\n          status: 'blocked',\n          current,\n          next,\n          action: blockerFnArgs.action,\n          proceed: () => resolve(false),\n          reset: () => resolve(true),\n        })\n      })\n\n      const canNavigateAsync = await promise\n      setResolver({\n        status: 'idle',\n        current: undefined,\n        next: undefined,\n        action: undefined,\n        proceed: undefined,\n        reset: undefined,\n      })\n\n      return canNavigateAsync\n    }\n\n    return disabled\n      ? undefined\n      : history.block({ blockerFn: blockerFnComposed, enableBeforeUnload })\n  }, [\n    shouldBlockFn,\n    enableBeforeUnload,\n    disabled,\n    withResolver,\n    history,\n    router,\n  ])\n\n  return resolver\n}\n\nconst _resolvePromptBlockerArgs = (\n  props: PromptProps | LegacyPromptProps,\n): UseBlockerOpts => {\n  if ('shouldBlockFn' in props) {\n    return { ...props }\n  }\n\n  const shouldBlock = Boolean(props.condition ?? true)\n  const fn = props.blockerFn\n\n  const _customBlockerFn = async () => {\n    if (shouldBlock && fn !== undefined) {\n      return await fn()\n    }\n    return shouldBlock\n  }\n\n  return {\n    shouldBlockFn: _customBlockerFn,\n    enableBeforeUnload: shouldBlock,\n    withResolver: fn === undefined,\n  }\n}\n\nexport function Block<\n  TRouter extends AnyRouter = RegisteredRouter,\n  TWithResolver extends boolean = boolean,\n>(opts: PromptProps<TRouter, TWithResolver>): React.ReactNode\n\n/**\n *  @deprecated Use the UseBlockerOpts property instead\n */\nexport function Block(opts: LegacyPromptProps): React.ReactNode\n\nexport function Block(opts: PromptProps | LegacyPromptProps): React.ReactNode {\n  const { children, ...rest } = opts\n  const args = _resolvePromptBlockerArgs(rest)\n\n  const resolver = useBlocker(args)\n  return children\n    ? typeof children === 'function'\n      ? children(resolver as any)\n      : children\n    : null\n}\n\ntype LegacyPromptProps = {\n  blockerFn?: LegacyBlockerFn\n  condition?: boolean | any\n  children?: React.ReactNode | ((params: BlockerResolver) => React.ReactNode)\n}\n\ntype PromptProps<\n  TRouter extends AnyRouter = RegisteredRouter,\n  TWithResolver extends boolean = boolean,\n  TParams = TWithResolver extends true ? BlockerResolver<TRouter> : void,\n> = UseBlockerOpts<TRouter, TWithResolver> & {\n  children?: React.ReactNode | ((params: TParams) => React.ReactNode)\n}\n"],"names":["shouldBlock","_customBlockerFn","useRouter","React"],"mappings":"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"}