{"version":3,"file":"Transitioner.cjs","names":[],"sources":["../../src/Transitioner.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport { getLocationChangeInfo, trimPathRight } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport type { NavigationRef } from 'solid-js'\nimport type { AnyRouteMatch } from '@tanstack/router-core'\n\n/**\n * Solid's observe tier (`OBSERVE` is defined on the dev and observe builds,\n * undefined in production) attributes what the user waited on to the\n * navigation that caused it. The rule for every router is the same: wrap the\n * write whose landing is the destination showing, and pass `at` when the\n * request predates that write. Here that write is the match publish inside\n * `startTransition` — the loaders were awaited in router-core before it —\n * so the ref names the destination route from the expected matches and\n * dates from the history change that started the load. The pending offer\n * (`offerPending`, a match with `status: 'pending'`) is not the destination\n * and is published undeclared; the initial load and a same-location reload\n * are not navigations.\n */\nfunction describeNavigation(\n  router: ReturnType<typeof useRouter>,\n  expected: Array<AnyRouteMatch>,\n  at: number | undefined,\n): NavigationRef | undefined {\n  if (expected.some((match) => match.status === 'pending')) return\n  const to = router.latestLocation\n  const from = router.stores.resolvedLocation.get()\n  // Nothing shown yet (the initial load), or a reload of what is shown.\n  if (!from || from.href === to.href) return\n  const leaf = expected[expected.length - 1]\n  const ref: NavigationRef = {\n    kind: 'navigation',\n    name: leaf?.fullPath || to.pathname,\n    to: to.pathname,\n    from: from.pathname,\n  }\n  if (leaf && Object.keys(leaf.params).length) ref.params = leaf.params\n  if (at !== undefined) ref.at = at\n  return ref\n}\n\nfunction getResolvedLocation(router: ReturnType<typeof useRouter>) {\n  const resolvedLocation = router.stores.resolvedLocation.get()\n  if (\n    resolvedLocation?.href === router.latestLocation.href &&\n    resolvedLocation.state.__TSR_key === router.latestLocation.state.__TSR_key\n  ) {\n    return resolvedLocation\n  }\n  return\n}\n\nexport function Transitioner() {\n  const router = useRouter()\n\n  type Ack = [\n    expected: Array<AnyRouteMatch>,\n    resolve: (rendered: boolean) => void,\n  ]\n  const acks: Array<Ack> = []\n  let committed: Array<AnyRouteMatch> | undefined\n\n  const isCommitted = (expected: Array<AnyRouteMatch>) =>\n    !!committed &&\n    committed.length === expected.length &&\n    expected.every((match, index) => committed![index] === match)\n\n  // When the history changed since the last declared publish: the moment\n  // the user asked, which is where the navigation's wait starts.\n  let requestedAt: number | undefined\n\n  // Ack when the commit's transition settles (the atomic swap), not when the\n  // flush parks it; superseded or rolled-back commits resolve false.\n  router.startTransition = (fn, expectedMatches) => {\n    if (isServer ?? router.isServer) {\n      fn()\n      return Promise.resolve(true)\n    }\n    return new Promise((resolve) => {\n      const ack: Ack = [expectedMatches, resolve]\n      acks.push(ack)\n      let publish = fn\n      if (Solid.OBSERVE !== undefined) {\n        const ref = describeNavigation(router, expectedMatches, requestedAt)\n        if (ref !== undefined) {\n          requestedAt = undefined\n          const observe = Solid.OBSERVE\n          publish = () => observe.attribution.withOrigin(ref, fn)\n        }\n      }\n      Solid.runWithOwner(null, publish)\n      try {\n        Solid.flush()\n      } catch {\n        // Solid auto-flushes when this is called from a reactive context.\n      }\n      // A commit that changed nothing produces no settlement to observe.\n      if (acks.includes(ack) && isCommitted(expectedMatches)) {\n        acks.splice(acks.indexOf(ack), 1)\n        resolve(true)\n      }\n    })\n  }\n\n  // No server early-return here or below: Solid 2 derives hydration keys\n  // from the reactive owner tree, so the server must register the same slots\n  // as the client. The callbacks themselves never run on the server.\n  Solid.createEffect(\n    () => router.stores.matches.get(),\n    (current) => {\n      committed = current\n      if (acks.length) {\n        for (const [expected, resolve] of acks.splice(0)) {\n          resolve(isCommitted(expected))\n        }\n      }\n    },\n  )\n\n  Solid.onSettled(() => {\n    const unsub = router.history.subscribe(() => {\n      requestedAt ??= performance.now()\n      queueMicrotask(() => router.load().catch(console.error))\n    })\n\n    // The URL may have changed synchronously between render and settlement.\n    router.updateLatestLocation()\n    const nextLocation = router.buildLocation({\n      to: router.latestLocation.pathname,\n      search: true,\n      params: true,\n      hash: true,\n      state: true,\n      _includeValidateSearch: true,\n    })\n\n    if (\n      trimPathRight(router.latestLocation.publicHref) !==\n      trimPathRight(nextLocation.publicHref)\n    ) {\n      router.commitLocation({\n        ...nextLocation,\n        replace: true,\n        ignoreBlocker: true,\n      })\n      return unsub\n    }\n\n    if (!getResolvedLocation(router) && !router._tx) {\n      queueMicrotask(() => router.load().catch(console.error))\n    }\n\n    return unsub\n  })\n\n  return null\n}\n\nexport function Rendered() {\n  const router = useRouter()\n  Solid.onSettled(() => {\n    const resolvedLocation = getResolvedLocation(router)\n    if (resolvedLocation) {\n      router.emit({\n        type: 'onRendered',\n        ...getLocationChangeInfo(resolvedLocation, resolvedLocation),\n      })\n    }\n  })\n  return null\n}\n"],"mappings":"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"}