{"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 { describeInitial, describeNavigation, takeRequest } from './observe'\nimport type { NavigationHop, NavigationRequest } from './observe'\nimport type { HistoryLocation, RouterHistory } from '@tanstack/history'\nimport type { AnyRouteMatch, ParsedLocation } from '@tanstack/router-core'\n\n/** What the history tells its subscribers. */\ntype HistoryChange = Parameters<Parameters<RouterHistory['subscribe']>[0]>[0]\n\n/** The history change was the arrival's own canonicalization, not a request. */\nconst ARRIVAL = Symbol()\n\n/** A navigation requested and not yet published. */\ninterface PendingNavigation extends NavigationRequest {\n  /** Where it is headed now. */\n  location: HistoryLocation\n  /** The destinations it was sent on from, in order. */\n  hops: Array<NavigationHop>\n}\n\n/**\n * `offerPending`'s publish: a match still `pending` at or above the\n * not-found boundary. The matches below a not-found never load, and stay\n * `pending` in the publish that lands; an offer whose pending match is\n * below one already shows the destination, the not-found.\n */\nfunction isPendingOffer(matches: Array<AnyRouteMatch>) {\n  for (const match of matches) {\n    if (match.status === 'pending') return true\n    if (match._notFound) return false\n  }\n  return false\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  // Solid's observe tier attributes what the user waited on to the\n  // navigation that caused it: wrap the write whose landing is the\n  // destination showing — here the match publish, after router-core awaited\n  // the loaders — and describe the request, which predates it. The first\n  // history change since the last publish is that request: when the user\n  // asked, and the interaction they asked in, gone from the stack by the time\n  // the publish runs. A push or replace while it is pending (a redirect, or\n  // another navigation) sends it elsewhere, as `@solidjs/router` folds one:\n  // a hop. `ARRIVAL` when the change was the arrival being canonicalized\n  // (below): the initial declaration already covers it.\n  let request: PendingNavigation | typeof ARRIVAL | undefined\n  let canonicalizing = false\n  // The location the initial declaration names, canonical: what a navigation\n  // is from until the first publish resolves one (a redirect while it loads).\n  let arrival: ParsedLocation | 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      // The pending offer (`offerPending`) is not the destination: published\n      // undeclared, the request kept for the publish that lands. Every other\n      // publish answers the request.\n      if (Solid.OBSERVE !== undefined && !isPendingOffer(expectedMatches)) {\n        const answered = request\n        request = undefined\n        const refs =\n          answered === undefined || answered === ARRIVAL\n            ? undefined\n            : describeNavigation(\n                router,\n                answered,\n                router.stores.resolvedLocation.get() ?? arrival,\n                answered.hops,\n              )\n        if (refs !== undefined) {\n          const observe = Solid.OBSERVE\n          publish = refs.reduceRight<() => void>(\n            (inner, ref) => () => observe.attribution.withOrigin(ref, inner),\n            fn,\n          )\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      ({ location, action }: HistoryChange) => {\n        if (Solid.OBSERVE !== undefined) {\n          // A push or replace was requested through `commitLocation`, maybe\n          // before an `await` on the blockers; anything else is the browser\n          // moving, requested now.\n          const write = action.type === 'PUSH' || action.type === 'REPLACE'\n          const noted = write ? takeRequest(router) : undefined\n          if (canonicalizing) request ??= ARRIVAL\n          else if (write && request !== undefined && request !== ARRIVAL) {\n            request.hops.push({\n              location: router.parseLocation(request.location),\n              at: noted?.at ?? performance.now(),\n            })\n            request.location = location\n          } else {\n            // A new request: the browser moving (back, forward) supersedes a\n            // pending one rather than redirecting it, as in `@solidjs/router`.\n            request = {\n              ...(noted ?? {\n                at: performance.now(),\n                interaction: Solid.OBSERVE.attribution.currentOrigin(),\n              }),\n              location,\n              hops: [],\n            }\n          }\n        }\n        queueMicrotask(() => router.load().catch(console.error))\n      },\n    )\n\n    // The route the document arrived on is declared around establishing it,\n    // canonicalization included, as `@solidjs/router` does: the record\n    // names the canonical location, and the commit is the arrival's.\n    const establish = () => {\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        arrival = nextLocation\n        // The history notifies synchronously inside the commit (no blocker\n        // to await), so the subscriber above sees the flag.\n        canonicalizing = true\n        try {\n          router.commitLocation({\n            ...nextLocation,\n            replace: true,\n            ignoreBlocker: true,\n          })\n        } finally {\n          canonicalizing = false\n        }\n        return\n      }\n\n      arrival = router.latestLocation\n      if (!getResolvedLocation(router) && !router._tx) {\n        queueMicrotask(() => router.load().catch(console.error))\n      }\n    }\n\n    const observe = Solid.OBSERVE\n    if (observe !== undefined) {\n      observe.attribution.withOrigin(\n        describeInitial(router, () => arrival ?? router.latestLocation),\n        establish,\n      )\n    } else establish()\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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"}