@tanstack/history 0.0.1-beta.245 → 0.0.1-beta.246

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,26 +31,20 @@ function createHistory(opts) {
31
31
  let location = opts.getLocation();
32
32
  let subscribers = new Set();
33
33
  let blockers = [];
34
- let queue = [];
35
34
  const onUpdate = () => {
36
35
  location = opts.getLocation();
37
36
  subscribers.forEach(subscriber => subscriber());
38
37
  };
39
- const tryUnblock = () => {
38
+ const tryNavigation = task => {
40
39
  if (blockers.length) {
41
- blockers[0]?.(tryUnblock, () => {
42
- blockers = [];
43
- stopBlocking();
44
- });
45
- return;
46
- }
47
- while (queue.length) {
48
- queue.shift()?.();
40
+ for (let blocker of blockers) {
41
+ if (!window.confirm(blocker.message)) {
42
+ opts.onBlocked?.(onUpdate);
43
+ return;
44
+ }
45
+ }
49
46
  }
50
- };
51
- const queueTask = task => {
52
- queue.push(task);
53
- tryUnblock();
47
+ task();
54
48
  };
55
49
  return {
56
50
  get location() {
@@ -64,41 +58,44 @@ function createHistory(opts) {
64
58
  },
65
59
  push: (path, state) => {
66
60
  state = assignKey(state);
67
- queueTask(() => {
61
+ tryNavigation(() => {
68
62
  opts.pushState(path, state, onUpdate);
69
63
  });
70
64
  },
71
65
  replace: (path, state) => {
72
66
  state = assignKey(state);
73
- queueTask(() => {
67
+ tryNavigation(() => {
74
68
  opts.replaceState(path, state, onUpdate);
75
69
  });
76
70
  },
77
71
  go: index => {
78
- queueTask(() => {
72
+ tryNavigation(() => {
79
73
  opts.go(index);
80
74
  });
81
75
  },
82
76
  back: () => {
83
- queueTask(() => {
77
+ tryNavigation(() => {
84
78
  opts.back();
85
79
  });
86
80
  },
87
81
  forward: () => {
88
- queueTask(() => {
82
+ tryNavigation(() => {
89
83
  opts.forward();
90
84
  });
91
85
  },
92
86
  createHref: str => opts.createHref(str),
93
- block: cb => {
94
- blockers.push(cb);
87
+ block: message => {
88
+ const payload = {
89
+ message
90
+ };
91
+ blockers.push(payload);
95
92
  if (blockers.length === 1) {
96
93
  addEventListener(beforeUnloadEvent, beforeUnloadListener, {
97
94
  capture: true
98
95
  });
99
96
  }
100
97
  return () => {
101
- blockers = blockers.filter(b => b !== cb);
98
+ blockers = blockers.filter(b => b !== payload);
102
99
  if (!blockers.length) {
103
100
  stopBlocking();
104
101
  }
@@ -139,6 +136,7 @@ function createBrowserHistory(opts) {
139
136
  const getHref = opts?.getHref ?? (() => `${window.location.pathname}${window.location.search}${window.location.hash}`);
140
137
  const createHref = opts?.createHref ?? (path => path);
141
138
  let currentLocation = parseLocation(getHref(), window.history.state);
139
+ let rollbackLocation;
142
140
  const getLocation = () => currentLocation;
143
141
  let next;
144
142
 
@@ -169,12 +167,16 @@ function createBrowserHistory(opts) {
169
167
  // Reset the nextIsPush flag and clear the scheduled update
170
168
  next = undefined;
171
169
  scheduled = undefined;
170
+ rollbackLocation = undefined;
172
171
  });
173
172
  };
174
173
 
175
174
  // This function queues up a call to update the browser history
176
175
  const queueHistoryAction = (type, path, state, onUpdate) => {
177
176
  const href = createHref(path);
177
+ if (!scheduled) {
178
+ rollbackLocation = currentLocation;
179
+ }
178
180
 
179
181
  // Update the location in memory
180
182
  currentLocation = parseLocation(href, state);
@@ -185,6 +187,7 @@ function createBrowserHistory(opts) {
185
187
  state,
186
188
  isPush: next?.isPush || type === 'push'
187
189
  };
190
+
188
191
  // Notify subscribers
189
192
  onUpdate();
190
193
  if (!scheduled) {
@@ -212,6 +215,15 @@ function createBrowserHistory(opts) {
212
215
  window.history.replaceState = originalReplaceState;
213
216
  window.removeEventListener(pushStateEvent, onPushPop);
214
217
  window.removeEventListener(popStateEvent, onPushPop);
218
+ },
219
+ onBlocked: onUpdate => {
220
+ // If a navigation is blocked, we need to rollback the location
221
+ // that we optimistically updated in memory.
222
+ if (rollbackLocation && currentLocation !== rollbackLocation) {
223
+ currentLocation = rollbackLocation;
224
+ // Notify subscribers
225
+ onUpdate();
226
+ }
215
227
  }
216
228
  });
217
229
  window.addEventListener(pushStateEvent, onPushPop);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["// While the public API was clearly inspired by the \"history\" npm package,\n// This implementation attempts to be more lightweight by\n// making assumptions about the way TanStack Router works\n\nexport interface RouterHistory {\n location: HistoryLocation\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any) => void\n replace: (path: string, state?: any) => void\n go: (index: number) => void\n back: () => void\n forward: () => void\n createHref: (href: string) => string\n block: (blockerFn: BlockerFn) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n}\n\nexport interface HistoryLocation extends ParsedPath {\n state: HistoryState\n}\n\nexport interface ParsedPath {\n href: string\n pathname: string\n search: string\n hash: string\n}\n\nexport interface HistoryState {\n key: string\n}\n\ntype BlockerFn = (retry: () => void, cancel: () => void) => void\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-ignore\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nfunction createHistory(opts: {\n getLocation: () => HistoryLocation\n pushState: (path: string, state: any, onUpdate: () => void) => void\n replaceState: (path: string, state: any, onUpdate: () => void) => void\n go: (n: number) => void\n back: () => void\n forward: () => void\n createHref: (path: string) => string\n flush?: () => void\n destroy?: () => void\n}): RouterHistory {\n let location = opts.getLocation()\n let subscribers = new Set<() => void>()\n let blockers: BlockerFn[] = []\n let queue: (() => void)[] = []\n\n const onUpdate = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryUnblock = () => {\n if (blockers.length) {\n blockers[0]?.(tryUnblock, () => {\n blockers = []\n stopBlocking()\n })\n return\n }\n\n while (queue.length) {\n queue.shift()?.()\n }\n }\n\n const queueTask = (task: () => void) => {\n queue.push(task)\n tryUnblock()\n }\n\n return {\n get location() {\n return location\n },\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path: string, state: any) => {\n state = assignKey(state)\n queueTask(() => {\n opts.pushState(path, state, onUpdate)\n })\n },\n replace: (path: string, state: any) => {\n state = assignKey(state)\n queueTask(() => {\n opts.replaceState(path, state, onUpdate)\n })\n },\n go: (index) => {\n queueTask(() => {\n opts.go(index)\n })\n },\n back: () => {\n queueTask(() => {\n opts.back()\n })\n },\n forward: () => {\n queueTask(() => {\n opts.forward()\n })\n },\n createHref: (str) => opts.createHref(str),\n block: (cb) => {\n blockers.push(cb)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== cb)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify: onUpdate,\n }\n}\n\nfunction assignKey(state: HistoryState) {\n if (!state) {\n state = {} as HistoryState\n }\n return {\n ...state,\n key: createRandomKey(),\n }\n}\n\n/**\n * Creates a history object that can be used to interact with the browser's\n * navigation. This is a lightweight API wrapping the browser's native methods.\n * It is designed to work with TanStack Router, but could be used as a standalone API as well.\n * IMPORTANT: This API implements history throttling via a microtask to prevent\n * excessive calls to the history API. In some browsers, calling history.pushState or\n * history.replaceState in quick succession can cause the browser to ignore subsequent\n * calls. This API smooths out those differences and ensures that your application\n * state will *eventually* match the browser state. In most cases, this is not a problem,\n * but if you need to ensure that the browser state is up to date, you can use the\n * `history.flush` method to immediately flush all pending state changes to the browser URL.\n * @param opts\n * @param opts.getHref A function that returns the current href (path + search + hash)\n * @param opts.createHref A function that takes a path and returns a href (path + search + hash)\n * @returns A history instance\n */\nexport function createBrowserHistory(opts?: {\n getHref?: () => string\n createHref?: (path: string) => string\n}): RouterHistory {\n const getHref =\n opts?.getHref ??\n (() =>\n `${window.location.pathname}${window.location.search}${window.location.hash}`)\n\n const createHref = opts?.createHref ?? ((path) => path)\n\n let currentLocation = parseLocation(getHref(), window.history.state)\n\n const getLocation = () => currentLocation\n\n let next:\n | undefined\n | {\n // This is the latest location that we were attempting to push/replace\n href: string\n // This is the latest state that we were attempting to push/replace\n state: any\n // This is the latest type that we were attempting to push/replace\n isPush: boolean\n }\n\n // Because we are proactively updating the location\n // in memory before actually updating the browser history,\n // we need to track when we are doing this so we don't\n // notify subscribers twice on the last update.\n let tracking = true\n\n // We need to track the current scheduled update to prevent\n // multiple updates from being scheduled at the same time.\n let scheduled: Promise<void> | undefined\n\n // This function is a wrapper to prevent any of the callback's\n // side effects from causing a subscriber notification\n const untrack = (fn: () => void) => {\n tracking = false\n fn()\n tracking = true\n }\n\n // This function flushes the next update to the browser history\n const flush = () => {\n // Do not notify subscribers about this push/replace call\n untrack(() => {\n if (!next) return\n window.history[next.isPush ? 'pushState' : 'replaceState'](\n next.state,\n '',\n next.href,\n )\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n })\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n path: string,\n state: any,\n onUpdate: () => void,\n ) => {\n const href = createHref(path)\n\n // Update the location in memory\n currentLocation = parseLocation(href, state)\n\n // Keep track of the next location we need to flush to the URL\n next = {\n href,\n state,\n isPush: next?.isPush || type === 'push',\n }\n // Notify subscribers\n onUpdate()\n\n if (!scheduled) {\n // Schedule an update to the browser history\n scheduled = Promise.resolve().then(() => flush())\n }\n }\n\n const onPushPop = () => {\n currentLocation = parseLocation(getHref(), window.history.state)\n history.notify()\n }\n\n var originalPushState = window.history.pushState\n var originalReplaceState = window.history.replaceState\n\n const history = createHistory({\n getLocation,\n pushState: (path, state, onUpdate) =>\n queueHistoryAction('push', path, state, onUpdate),\n replaceState: (path, state, onUpdate) =>\n queueHistoryAction('replace', path, state, onUpdate),\n back: () => window.history.back(),\n forward: () => window.history.forward(),\n go: (n) => window.history.go(n),\n createHref: (path) => createHref(path),\n flush,\n destroy: () => {\n window.history.pushState = originalPushState\n window.history.replaceState = originalReplaceState\n window.removeEventListener(pushStateEvent, onPushPop)\n window.removeEventListener(popStateEvent, onPushPop)\n },\n })\n\n window.addEventListener(pushStateEvent, onPushPop)\n window.addEventListener(popStateEvent, onPushPop)\n\n window.history.pushState = function () {\n let res = originalPushState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n window.history.replaceState = function () {\n let res = originalReplaceState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(): RouterHistory {\n return createBrowserHistory({\n getHref: () => window.location.hash.substring(1),\n createHref: (path) => `#${path}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: string[]\n initialIndex?: number\n } = {\n initialEntries: ['/'],\n },\n): RouterHistory {\n const entries = opts.initialEntries\n let index = opts.initialIndex ?? entries.length - 1\n let currentState = {\n key: createRandomKey(),\n } as HistoryState\n\n const getLocation = () => parseLocation(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n pushState: (path, state) => {\n currentState = state\n entries.push(path)\n index++\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n index--\n },\n forward: () => {\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => window.history.go(n),\n createHref: (path) => path,\n })\n}\n\nfunction parseLocation(href: string, state: HistoryState): HistoryLocation {\n let hashIndex = href.indexOf('#')\n let searchIndex = href.indexOf('?')\n\n return {\n href,\n pathname: href.substring(\n 0,\n hashIndex > 0\n ? searchIndex > 0\n ? Math.min(hashIndex, searchIndex)\n : hashIndex\n : searchIndex > 0\n ? searchIndex\n : href.length,\n ),\n hash: hashIndex > -1 ? href.substring(hashIndex) : '',\n search:\n searchIndex > -1\n ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex)\n : '',\n state: state || {},\n }\n}\n\n// Thanks co-pilot!\nfunction createRandomKey() {\n return (Math.random() + 1).toString(36).substring(7)\n}\n"],"names":["pushStateEvent","popStateEvent","beforeUnloadEvent","beforeUnloadListener","event","preventDefault","returnValue","stopBlocking","removeEventListener","capture","createHistory","opts","location","getLocation","subscribers","Set","blockers","queue","onUpdate","forEach","subscriber","tryUnblock","length","shift","queueTask","task","push","subscribe","cb","add","delete","path","state","assignKey","pushState","replace","replaceState","go","index","back","forward","createHref","str","block","addEventListener","filter","b","flush","destroy","notify","key","createRandomKey","createBrowserHistory","getHref","window","pathname","search","hash","currentLocation","parseLocation","history","next","tracking","scheduled","untrack","fn","isPush","href","undefined","queueHistoryAction","type","Promise","resolve","then","onPushPop","originalPushState","originalReplaceState","n","res","apply","arguments","createHashHistory","substring","createMemoryHistory","initialEntries","entries","initialIndex","currentState","Math","min","hashIndex","indexOf","searchIndex","slice","random","toString"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["// While the public API was clearly inspired by the \"history\" npm package,\n// This implementation attempts to be more lightweight by\n// making assumptions about the way TanStack Router works\n\nexport interface RouterHistory {\n location: HistoryLocation\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any) => void\n replace: (path: string, state?: any) => void\n go: (index: number) => void\n back: () => void\n forward: () => void\n createHref: (href: string) => string\n block: (message: string) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n}\n\nexport interface HistoryLocation extends ParsedPath {\n state: HistoryState\n}\n\nexport interface ParsedPath {\n href: string\n pathname: string\n search: string\n hash: string\n}\n\nexport interface HistoryState {\n key: string\n}\n\ntype Blocker = {\n message: string\n}\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-ignore\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nfunction createHistory(opts: {\n getLocation: () => HistoryLocation\n pushState: (path: string, state: any, onUpdate: () => void) => void\n replaceState: (path: string, state: any, onUpdate: () => void) => void\n go: (n: number) => void\n back: () => void\n forward: () => void\n createHref: (path: string) => string\n flush?: () => void\n destroy?: () => void\n onBlocked?: (onUpdate: () => void) => void\n}): RouterHistory {\n let location = opts.getLocation()\n let subscribers = new Set<() => void>()\n let blockers: Blocker[] = []\n\n const onUpdate = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryNavigation = (task: () => void) => {\n if (blockers.length) {\n for (let blocker of blockers) {\n if (!window.confirm(blocker.message)) {\n opts.onBlocked?.(onUpdate)\n return\n }\n }\n }\n\n task()\n }\n\n return {\n get location() {\n return location\n },\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path: string, state: any) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.pushState(path, state, onUpdate)\n })\n },\n replace: (path: string, state: any) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.replaceState(path, state, onUpdate)\n })\n },\n go: (index) => {\n tryNavigation(() => {\n opts.go(index)\n })\n },\n back: () => {\n tryNavigation(() => {\n opts.back()\n })\n },\n forward: () => {\n tryNavigation(() => {\n opts.forward()\n })\n },\n createHref: (str) => opts.createHref(str),\n block: (message) => {\n const payload: Blocker = {\n message,\n }\n\n blockers.push(payload)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== payload)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify: onUpdate,\n }\n}\n\nfunction assignKey(state: HistoryState) {\n if (!state) {\n state = {} as HistoryState\n }\n return {\n ...state,\n key: createRandomKey(),\n }\n}\n\n/**\n * Creates a history object that can be used to interact with the browser's\n * navigation. This is a lightweight API wrapping the browser's native methods.\n * It is designed to work with TanStack Router, but could be used as a standalone API as well.\n * IMPORTANT: This API implements history throttling via a microtask to prevent\n * excessive calls to the history API. In some browsers, calling history.pushState or\n * history.replaceState in quick succession can cause the browser to ignore subsequent\n * calls. This API smooths out those differences and ensures that your application\n * state will *eventually* match the browser state. In most cases, this is not a problem,\n * but if you need to ensure that the browser state is up to date, you can use the\n * `history.flush` method to immediately flush all pending state changes to the browser URL.\n * @param opts\n * @param opts.getHref A function that returns the current href (path + search + hash)\n * @param opts.createHref A function that takes a path and returns a href (path + search + hash)\n * @returns A history instance\n */\nexport function createBrowserHistory(opts?: {\n getHref?: () => string\n createHref?: (path: string) => string\n}): RouterHistory {\n const getHref =\n opts?.getHref ??\n (() =>\n `${window.location.pathname}${window.location.search}${window.location.hash}`)\n\n const createHref = opts?.createHref ?? ((path) => path)\n\n let currentLocation = parseLocation(getHref(), window.history.state)\n let rollbackLocation: HistoryLocation | undefined\n\n const getLocation = () => currentLocation\n\n let next:\n | undefined\n | {\n // This is the latest location that we were attempting to push/replace\n href: string\n // This is the latest state that we were attempting to push/replace\n state: any\n // This is the latest type that we were attempting to push/replace\n isPush: boolean\n }\n\n // Because we are proactively updating the location\n // in memory before actually updating the browser history,\n // we need to track when we are doing this so we don't\n // notify subscribers twice on the last update.\n let tracking = true\n\n // We need to track the current scheduled update to prevent\n // multiple updates from being scheduled at the same time.\n let scheduled: Promise<void> | undefined\n\n // This function is a wrapper to prevent any of the callback's\n // side effects from causing a subscriber notification\n const untrack = (fn: () => void) => {\n tracking = false\n fn()\n tracking = true\n }\n\n // This function flushes the next update to the browser history\n const flush = () => {\n // Do not notify subscribers about this push/replace call\n untrack(() => {\n if (!next) return\n window.history[next.isPush ? 'pushState' : 'replaceState'](\n next.state,\n '',\n next.href,\n )\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n rollbackLocation = undefined\n })\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n path: string,\n state: any,\n onUpdate: () => void,\n ) => {\n const href = createHref(path)\n\n if (!scheduled) {\n rollbackLocation = currentLocation\n }\n\n // Update the location in memory\n currentLocation = parseLocation(href, state)\n\n // Keep track of the next location we need to flush to the URL\n next = {\n href,\n state,\n isPush: next?.isPush || type === 'push',\n }\n\n // Notify subscribers\n onUpdate()\n\n if (!scheduled) {\n // Schedule an update to the browser history\n scheduled = Promise.resolve().then(() => flush())\n }\n }\n\n const onPushPop = () => {\n currentLocation = parseLocation(getHref(), window.history.state)\n history.notify()\n }\n\n var originalPushState = window.history.pushState\n var originalReplaceState = window.history.replaceState\n\n const history = createHistory({\n getLocation,\n pushState: (path, state, onUpdate) =>\n queueHistoryAction('push', path, state, onUpdate),\n replaceState: (path, state, onUpdate) =>\n queueHistoryAction('replace', path, state, onUpdate),\n back: () => window.history.back(),\n forward: () => window.history.forward(),\n go: (n) => window.history.go(n),\n createHref: (path) => createHref(path),\n flush,\n destroy: () => {\n window.history.pushState = originalPushState\n window.history.replaceState = originalReplaceState\n window.removeEventListener(pushStateEvent, onPushPop)\n window.removeEventListener(popStateEvent, onPushPop)\n },\n onBlocked: (onUpdate) => {\n // If a navigation is blocked, we need to rollback the location\n // that we optimistically updated in memory.\n if (rollbackLocation && currentLocation !== rollbackLocation) {\n currentLocation = rollbackLocation\n // Notify subscribers\n onUpdate()\n }\n },\n })\n\n window.addEventListener(pushStateEvent, onPushPop)\n window.addEventListener(popStateEvent, onPushPop)\n\n window.history.pushState = function () {\n let res = originalPushState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n window.history.replaceState = function () {\n let res = originalReplaceState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(): RouterHistory {\n return createBrowserHistory({\n getHref: () => window.location.hash.substring(1),\n createHref: (path) => `#${path}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: string[]\n initialIndex?: number\n } = {\n initialEntries: ['/'],\n },\n): RouterHistory {\n const entries = opts.initialEntries\n let index = opts.initialIndex ?? entries.length - 1\n let currentState = {\n key: createRandomKey(),\n } as HistoryState\n\n const getLocation = () => parseLocation(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n pushState: (path, state) => {\n currentState = state\n entries.push(path)\n index++\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n index--\n },\n forward: () => {\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => window.history.go(n),\n createHref: (path) => path,\n })\n}\n\nfunction parseLocation(href: string, state: HistoryState): HistoryLocation {\n let hashIndex = href.indexOf('#')\n let searchIndex = href.indexOf('?')\n\n return {\n href,\n pathname: href.substring(\n 0,\n hashIndex > 0\n ? searchIndex > 0\n ? Math.min(hashIndex, searchIndex)\n : hashIndex\n : searchIndex > 0\n ? searchIndex\n : href.length,\n ),\n hash: hashIndex > -1 ? href.substring(hashIndex) : '',\n search:\n searchIndex > -1\n ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex)\n : '',\n state: state || {},\n }\n}\n\n// Thanks co-pilot!\nfunction createRandomKey() {\n return (Math.random() + 1).toString(36).substring(7)\n}\n"],"names":["pushStateEvent","popStateEvent","beforeUnloadEvent","beforeUnloadListener","event","preventDefault","returnValue","stopBlocking","removeEventListener","capture","createHistory","opts","location","getLocation","subscribers","Set","blockers","onUpdate","forEach","subscriber","tryNavigation","task","length","blocker","window","confirm","message","onBlocked","subscribe","cb","add","delete","push","path","state","assignKey","pushState","replace","replaceState","go","index","back","forward","createHref","str","block","payload","addEventListener","filter","b","flush","destroy","notify","key","createRandomKey","createBrowserHistory","getHref","pathname","search","hash","currentLocation","parseLocation","history","rollbackLocation","next","tracking","scheduled","untrack","fn","isPush","href","undefined","queueHistoryAction","type","Promise","resolve","then","onPushPop","originalPushState","originalReplaceState","n","res","apply","arguments","createHashHistory","substring","createMemoryHistory","initialEntries","entries","initialIndex","currentState","Math","min","hashIndex","indexOf","searchIndex","slice","random","toString"],"mappings":"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"}
@@ -29,26 +29,20 @@ function createHistory(opts) {
29
29
  let location = opts.getLocation();
30
30
  let subscribers = new Set();
31
31
  let blockers = [];
32
- let queue = [];
33
32
  const onUpdate = () => {
34
33
  location = opts.getLocation();
35
34
  subscribers.forEach(subscriber => subscriber());
36
35
  };
37
- const tryUnblock = () => {
36
+ const tryNavigation = task => {
38
37
  if (blockers.length) {
39
- blockers[0]?.(tryUnblock, () => {
40
- blockers = [];
41
- stopBlocking();
42
- });
43
- return;
44
- }
45
- while (queue.length) {
46
- queue.shift()?.();
38
+ for (let blocker of blockers) {
39
+ if (!window.confirm(blocker.message)) {
40
+ opts.onBlocked?.(onUpdate);
41
+ return;
42
+ }
43
+ }
47
44
  }
48
- };
49
- const queueTask = task => {
50
- queue.push(task);
51
- tryUnblock();
45
+ task();
52
46
  };
53
47
  return {
54
48
  get location() {
@@ -62,41 +56,44 @@ function createHistory(opts) {
62
56
  },
63
57
  push: (path, state) => {
64
58
  state = assignKey(state);
65
- queueTask(() => {
59
+ tryNavigation(() => {
66
60
  opts.pushState(path, state, onUpdate);
67
61
  });
68
62
  },
69
63
  replace: (path, state) => {
70
64
  state = assignKey(state);
71
- queueTask(() => {
65
+ tryNavigation(() => {
72
66
  opts.replaceState(path, state, onUpdate);
73
67
  });
74
68
  },
75
69
  go: index => {
76
- queueTask(() => {
70
+ tryNavigation(() => {
77
71
  opts.go(index);
78
72
  });
79
73
  },
80
74
  back: () => {
81
- queueTask(() => {
75
+ tryNavigation(() => {
82
76
  opts.back();
83
77
  });
84
78
  },
85
79
  forward: () => {
86
- queueTask(() => {
80
+ tryNavigation(() => {
87
81
  opts.forward();
88
82
  });
89
83
  },
90
84
  createHref: str => opts.createHref(str),
91
- block: cb => {
92
- blockers.push(cb);
85
+ block: message => {
86
+ const payload = {
87
+ message
88
+ };
89
+ blockers.push(payload);
93
90
  if (blockers.length === 1) {
94
91
  addEventListener(beforeUnloadEvent, beforeUnloadListener, {
95
92
  capture: true
96
93
  });
97
94
  }
98
95
  return () => {
99
- blockers = blockers.filter(b => b !== cb);
96
+ blockers = blockers.filter(b => b !== payload);
100
97
  if (!blockers.length) {
101
98
  stopBlocking();
102
99
  }
@@ -137,6 +134,7 @@ function createBrowserHistory(opts) {
137
134
  const getHref = opts?.getHref ?? (() => `${window.location.pathname}${window.location.search}${window.location.hash}`);
138
135
  const createHref = opts?.createHref ?? (path => path);
139
136
  let currentLocation = parseLocation(getHref(), window.history.state);
137
+ let rollbackLocation;
140
138
  const getLocation = () => currentLocation;
141
139
  let next;
142
140
 
@@ -167,12 +165,16 @@ function createBrowserHistory(opts) {
167
165
  // Reset the nextIsPush flag and clear the scheduled update
168
166
  next = undefined;
169
167
  scheduled = undefined;
168
+ rollbackLocation = undefined;
170
169
  });
171
170
  };
172
171
 
173
172
  // This function queues up a call to update the browser history
174
173
  const queueHistoryAction = (type, path, state, onUpdate) => {
175
174
  const href = createHref(path);
175
+ if (!scheduled) {
176
+ rollbackLocation = currentLocation;
177
+ }
176
178
 
177
179
  // Update the location in memory
178
180
  currentLocation = parseLocation(href, state);
@@ -183,6 +185,7 @@ function createBrowserHistory(opts) {
183
185
  state,
184
186
  isPush: next?.isPush || type === 'push'
185
187
  };
188
+
186
189
  // Notify subscribers
187
190
  onUpdate();
188
191
  if (!scheduled) {
@@ -210,6 +213,15 @@ function createBrowserHistory(opts) {
210
213
  window.history.replaceState = originalReplaceState;
211
214
  window.removeEventListener(pushStateEvent, onPushPop);
212
215
  window.removeEventListener(popStateEvent, onPushPop);
216
+ },
217
+ onBlocked: onUpdate => {
218
+ // If a navigation is blocked, we need to rollback the location
219
+ // that we optimistically updated in memory.
220
+ if (rollbackLocation && currentLocation !== rollbackLocation) {
221
+ currentLocation = rollbackLocation;
222
+ // Notify subscribers
223
+ onUpdate();
224
+ }
213
225
  }
214
226
  });
215
227
  window.addEventListener(pushStateEvent, onPushPop);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["// While the public API was clearly inspired by the \"history\" npm package,\n// This implementation attempts to be more lightweight by\n// making assumptions about the way TanStack Router works\n\nexport interface RouterHistory {\n location: HistoryLocation\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any) => void\n replace: (path: string, state?: any) => void\n go: (index: number) => void\n back: () => void\n forward: () => void\n createHref: (href: string) => string\n block: (blockerFn: BlockerFn) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n}\n\nexport interface HistoryLocation extends ParsedPath {\n state: HistoryState\n}\n\nexport interface ParsedPath {\n href: string\n pathname: string\n search: string\n hash: string\n}\n\nexport interface HistoryState {\n key: string\n}\n\ntype BlockerFn = (retry: () => void, cancel: () => void) => void\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-ignore\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nfunction createHistory(opts: {\n getLocation: () => HistoryLocation\n pushState: (path: string, state: any, onUpdate: () => void) => void\n replaceState: (path: string, state: any, onUpdate: () => void) => void\n go: (n: number) => void\n back: () => void\n forward: () => void\n createHref: (path: string) => string\n flush?: () => void\n destroy?: () => void\n}): RouterHistory {\n let location = opts.getLocation()\n let subscribers = new Set<() => void>()\n let blockers: BlockerFn[] = []\n let queue: (() => void)[] = []\n\n const onUpdate = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryUnblock = () => {\n if (blockers.length) {\n blockers[0]?.(tryUnblock, () => {\n blockers = []\n stopBlocking()\n })\n return\n }\n\n while (queue.length) {\n queue.shift()?.()\n }\n }\n\n const queueTask = (task: () => void) => {\n queue.push(task)\n tryUnblock()\n }\n\n return {\n get location() {\n return location\n },\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path: string, state: any) => {\n state = assignKey(state)\n queueTask(() => {\n opts.pushState(path, state, onUpdate)\n })\n },\n replace: (path: string, state: any) => {\n state = assignKey(state)\n queueTask(() => {\n opts.replaceState(path, state, onUpdate)\n })\n },\n go: (index) => {\n queueTask(() => {\n opts.go(index)\n })\n },\n back: () => {\n queueTask(() => {\n opts.back()\n })\n },\n forward: () => {\n queueTask(() => {\n opts.forward()\n })\n },\n createHref: (str) => opts.createHref(str),\n block: (cb) => {\n blockers.push(cb)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== cb)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify: onUpdate,\n }\n}\n\nfunction assignKey(state: HistoryState) {\n if (!state) {\n state = {} as HistoryState\n }\n return {\n ...state,\n key: createRandomKey(),\n }\n}\n\n/**\n * Creates a history object that can be used to interact with the browser's\n * navigation. This is a lightweight API wrapping the browser's native methods.\n * It is designed to work with TanStack Router, but could be used as a standalone API as well.\n * IMPORTANT: This API implements history throttling via a microtask to prevent\n * excessive calls to the history API. In some browsers, calling history.pushState or\n * history.replaceState in quick succession can cause the browser to ignore subsequent\n * calls. This API smooths out those differences and ensures that your application\n * state will *eventually* match the browser state. In most cases, this is not a problem,\n * but if you need to ensure that the browser state is up to date, you can use the\n * `history.flush` method to immediately flush all pending state changes to the browser URL.\n * @param opts\n * @param opts.getHref A function that returns the current href (path + search + hash)\n * @param opts.createHref A function that takes a path and returns a href (path + search + hash)\n * @returns A history instance\n */\nexport function createBrowserHistory(opts?: {\n getHref?: () => string\n createHref?: (path: string) => string\n}): RouterHistory {\n const getHref =\n opts?.getHref ??\n (() =>\n `${window.location.pathname}${window.location.search}${window.location.hash}`)\n\n const createHref = opts?.createHref ?? ((path) => path)\n\n let currentLocation = parseLocation(getHref(), window.history.state)\n\n const getLocation = () => currentLocation\n\n let next:\n | undefined\n | {\n // This is the latest location that we were attempting to push/replace\n href: string\n // This is the latest state that we were attempting to push/replace\n state: any\n // This is the latest type that we were attempting to push/replace\n isPush: boolean\n }\n\n // Because we are proactively updating the location\n // in memory before actually updating the browser history,\n // we need to track when we are doing this so we don't\n // notify subscribers twice on the last update.\n let tracking = true\n\n // We need to track the current scheduled update to prevent\n // multiple updates from being scheduled at the same time.\n let scheduled: Promise<void> | undefined\n\n // This function is a wrapper to prevent any of the callback's\n // side effects from causing a subscriber notification\n const untrack = (fn: () => void) => {\n tracking = false\n fn()\n tracking = true\n }\n\n // This function flushes the next update to the browser history\n const flush = () => {\n // Do not notify subscribers about this push/replace call\n untrack(() => {\n if (!next) return\n window.history[next.isPush ? 'pushState' : 'replaceState'](\n next.state,\n '',\n next.href,\n )\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n })\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n path: string,\n state: any,\n onUpdate: () => void,\n ) => {\n const href = createHref(path)\n\n // Update the location in memory\n currentLocation = parseLocation(href, state)\n\n // Keep track of the next location we need to flush to the URL\n next = {\n href,\n state,\n isPush: next?.isPush || type === 'push',\n }\n // Notify subscribers\n onUpdate()\n\n if (!scheduled) {\n // Schedule an update to the browser history\n scheduled = Promise.resolve().then(() => flush())\n }\n }\n\n const onPushPop = () => {\n currentLocation = parseLocation(getHref(), window.history.state)\n history.notify()\n }\n\n var originalPushState = window.history.pushState\n var originalReplaceState = window.history.replaceState\n\n const history = createHistory({\n getLocation,\n pushState: (path, state, onUpdate) =>\n queueHistoryAction('push', path, state, onUpdate),\n replaceState: (path, state, onUpdate) =>\n queueHistoryAction('replace', path, state, onUpdate),\n back: () => window.history.back(),\n forward: () => window.history.forward(),\n go: (n) => window.history.go(n),\n createHref: (path) => createHref(path),\n flush,\n destroy: () => {\n window.history.pushState = originalPushState\n window.history.replaceState = originalReplaceState\n window.removeEventListener(pushStateEvent, onPushPop)\n window.removeEventListener(popStateEvent, onPushPop)\n },\n })\n\n window.addEventListener(pushStateEvent, onPushPop)\n window.addEventListener(popStateEvent, onPushPop)\n\n window.history.pushState = function () {\n let res = originalPushState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n window.history.replaceState = function () {\n let res = originalReplaceState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(): RouterHistory {\n return createBrowserHistory({\n getHref: () => window.location.hash.substring(1),\n createHref: (path) => `#${path}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: string[]\n initialIndex?: number\n } = {\n initialEntries: ['/'],\n },\n): RouterHistory {\n const entries = opts.initialEntries\n let index = opts.initialIndex ?? entries.length - 1\n let currentState = {\n key: createRandomKey(),\n } as HistoryState\n\n const getLocation = () => parseLocation(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n pushState: (path, state) => {\n currentState = state\n entries.push(path)\n index++\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n index--\n },\n forward: () => {\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => window.history.go(n),\n createHref: (path) => path,\n })\n}\n\nfunction parseLocation(href: string, state: HistoryState): HistoryLocation {\n let hashIndex = href.indexOf('#')\n let searchIndex = href.indexOf('?')\n\n return {\n href,\n pathname: href.substring(\n 0,\n hashIndex > 0\n ? searchIndex > 0\n ? Math.min(hashIndex, searchIndex)\n : hashIndex\n : searchIndex > 0\n ? searchIndex\n : href.length,\n ),\n hash: hashIndex > -1 ? href.substring(hashIndex) : '',\n search:\n searchIndex > -1\n ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex)\n : '',\n state: state || {},\n }\n}\n\n// Thanks co-pilot!\nfunction createRandomKey() {\n return (Math.random() + 1).toString(36).substring(7)\n}\n"],"names":["pushStateEvent","popStateEvent","beforeUnloadEvent","beforeUnloadListener","event","preventDefault","returnValue","stopBlocking","removeEventListener","capture","createHistory","opts","location","getLocation","subscribers","Set","blockers","queue","onUpdate","forEach","subscriber","tryUnblock","length","shift","queueTask","task","push","subscribe","cb","add","delete","path","state","assignKey","pushState","replace","replaceState","go","index","back","forward","createHref","str","block","addEventListener","filter","b","flush","destroy","notify","key","createRandomKey","createBrowserHistory","getHref","window","pathname","search","hash","currentLocation","parseLocation","history","next","tracking","scheduled","untrack","fn","isPush","href","undefined","queueHistoryAction","type","Promise","resolve","then","onPushPop","originalPushState","originalReplaceState","n","res","apply","arguments","createHashHistory","substring","createMemoryHistory","initialEntries","entries","initialIndex","currentState","Math","min","hashIndex","indexOf","searchIndex","slice","random","toString"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["// While the public API was clearly inspired by the \"history\" npm package,\n// This implementation attempts to be more lightweight by\n// making assumptions about the way TanStack Router works\n\nexport interface RouterHistory {\n location: HistoryLocation\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any) => void\n replace: (path: string, state?: any) => void\n go: (index: number) => void\n back: () => void\n forward: () => void\n createHref: (href: string) => string\n block: (message: string) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n}\n\nexport interface HistoryLocation extends ParsedPath {\n state: HistoryState\n}\n\nexport interface ParsedPath {\n href: string\n pathname: string\n search: string\n hash: string\n}\n\nexport interface HistoryState {\n key: string\n}\n\ntype Blocker = {\n message: string\n}\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-ignore\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nfunction createHistory(opts: {\n getLocation: () => HistoryLocation\n pushState: (path: string, state: any, onUpdate: () => void) => void\n replaceState: (path: string, state: any, onUpdate: () => void) => void\n go: (n: number) => void\n back: () => void\n forward: () => void\n createHref: (path: string) => string\n flush?: () => void\n destroy?: () => void\n onBlocked?: (onUpdate: () => void) => void\n}): RouterHistory {\n let location = opts.getLocation()\n let subscribers = new Set<() => void>()\n let blockers: Blocker[] = []\n\n const onUpdate = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryNavigation = (task: () => void) => {\n if (blockers.length) {\n for (let blocker of blockers) {\n if (!window.confirm(blocker.message)) {\n opts.onBlocked?.(onUpdate)\n return\n }\n }\n }\n\n task()\n }\n\n return {\n get location() {\n return location\n },\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path: string, state: any) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.pushState(path, state, onUpdate)\n })\n },\n replace: (path: string, state: any) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.replaceState(path, state, onUpdate)\n })\n },\n go: (index) => {\n tryNavigation(() => {\n opts.go(index)\n })\n },\n back: () => {\n tryNavigation(() => {\n opts.back()\n })\n },\n forward: () => {\n tryNavigation(() => {\n opts.forward()\n })\n },\n createHref: (str) => opts.createHref(str),\n block: (message) => {\n const payload: Blocker = {\n message,\n }\n\n blockers.push(payload)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== payload)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify: onUpdate,\n }\n}\n\nfunction assignKey(state: HistoryState) {\n if (!state) {\n state = {} as HistoryState\n }\n return {\n ...state,\n key: createRandomKey(),\n }\n}\n\n/**\n * Creates a history object that can be used to interact with the browser's\n * navigation. This is a lightweight API wrapping the browser's native methods.\n * It is designed to work with TanStack Router, but could be used as a standalone API as well.\n * IMPORTANT: This API implements history throttling via a microtask to prevent\n * excessive calls to the history API. In some browsers, calling history.pushState or\n * history.replaceState in quick succession can cause the browser to ignore subsequent\n * calls. This API smooths out those differences and ensures that your application\n * state will *eventually* match the browser state. In most cases, this is not a problem,\n * but if you need to ensure that the browser state is up to date, you can use the\n * `history.flush` method to immediately flush all pending state changes to the browser URL.\n * @param opts\n * @param opts.getHref A function that returns the current href (path + search + hash)\n * @param opts.createHref A function that takes a path and returns a href (path + search + hash)\n * @returns A history instance\n */\nexport function createBrowserHistory(opts?: {\n getHref?: () => string\n createHref?: (path: string) => string\n}): RouterHistory {\n const getHref =\n opts?.getHref ??\n (() =>\n `${window.location.pathname}${window.location.search}${window.location.hash}`)\n\n const createHref = opts?.createHref ?? ((path) => path)\n\n let currentLocation = parseLocation(getHref(), window.history.state)\n let rollbackLocation: HistoryLocation | undefined\n\n const getLocation = () => currentLocation\n\n let next:\n | undefined\n | {\n // This is the latest location that we were attempting to push/replace\n href: string\n // This is the latest state that we were attempting to push/replace\n state: any\n // This is the latest type that we were attempting to push/replace\n isPush: boolean\n }\n\n // Because we are proactively updating the location\n // in memory before actually updating the browser history,\n // we need to track when we are doing this so we don't\n // notify subscribers twice on the last update.\n let tracking = true\n\n // We need to track the current scheduled update to prevent\n // multiple updates from being scheduled at the same time.\n let scheduled: Promise<void> | undefined\n\n // This function is a wrapper to prevent any of the callback's\n // side effects from causing a subscriber notification\n const untrack = (fn: () => void) => {\n tracking = false\n fn()\n tracking = true\n }\n\n // This function flushes the next update to the browser history\n const flush = () => {\n // Do not notify subscribers about this push/replace call\n untrack(() => {\n if (!next) return\n window.history[next.isPush ? 'pushState' : 'replaceState'](\n next.state,\n '',\n next.href,\n )\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n rollbackLocation = undefined\n })\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n path: string,\n state: any,\n onUpdate: () => void,\n ) => {\n const href = createHref(path)\n\n if (!scheduled) {\n rollbackLocation = currentLocation\n }\n\n // Update the location in memory\n currentLocation = parseLocation(href, state)\n\n // Keep track of the next location we need to flush to the URL\n next = {\n href,\n state,\n isPush: next?.isPush || type === 'push',\n }\n\n // Notify subscribers\n onUpdate()\n\n if (!scheduled) {\n // Schedule an update to the browser history\n scheduled = Promise.resolve().then(() => flush())\n }\n }\n\n const onPushPop = () => {\n currentLocation = parseLocation(getHref(), window.history.state)\n history.notify()\n }\n\n var originalPushState = window.history.pushState\n var originalReplaceState = window.history.replaceState\n\n const history = createHistory({\n getLocation,\n pushState: (path, state, onUpdate) =>\n queueHistoryAction('push', path, state, onUpdate),\n replaceState: (path, state, onUpdate) =>\n queueHistoryAction('replace', path, state, onUpdate),\n back: () => window.history.back(),\n forward: () => window.history.forward(),\n go: (n) => window.history.go(n),\n createHref: (path) => createHref(path),\n flush,\n destroy: () => {\n window.history.pushState = originalPushState\n window.history.replaceState = originalReplaceState\n window.removeEventListener(pushStateEvent, onPushPop)\n window.removeEventListener(popStateEvent, onPushPop)\n },\n onBlocked: (onUpdate) => {\n // If a navigation is blocked, we need to rollback the location\n // that we optimistically updated in memory.\n if (rollbackLocation && currentLocation !== rollbackLocation) {\n currentLocation = rollbackLocation\n // Notify subscribers\n onUpdate()\n }\n },\n })\n\n window.addEventListener(pushStateEvent, onPushPop)\n window.addEventListener(popStateEvent, onPushPop)\n\n window.history.pushState = function () {\n let res = originalPushState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n window.history.replaceState = function () {\n let res = originalReplaceState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(): RouterHistory {\n return createBrowserHistory({\n getHref: () => window.location.hash.substring(1),\n createHref: (path) => `#${path}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: string[]\n initialIndex?: number\n } = {\n initialEntries: ['/'],\n },\n): RouterHistory {\n const entries = opts.initialEntries\n let index = opts.initialIndex ?? entries.length - 1\n let currentState = {\n key: createRandomKey(),\n } as HistoryState\n\n const getLocation = () => parseLocation(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n pushState: (path, state) => {\n currentState = state\n entries.push(path)\n index++\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n index--\n },\n forward: () => {\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => window.history.go(n),\n createHref: (path) => path,\n })\n}\n\nfunction parseLocation(href: string, state: HistoryState): HistoryLocation {\n let hashIndex = href.indexOf('#')\n let searchIndex = href.indexOf('?')\n\n return {\n href,\n pathname: href.substring(\n 0,\n hashIndex > 0\n ? searchIndex > 0\n ? Math.min(hashIndex, searchIndex)\n : hashIndex\n : searchIndex > 0\n ? searchIndex\n : href.length,\n ),\n hash: hashIndex > -1 ? href.substring(hashIndex) : '',\n search:\n searchIndex > -1\n ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex)\n : '',\n state: state || {},\n }\n}\n\n// Thanks co-pilot!\nfunction createRandomKey() {\n return (Math.random() + 1).toString(36).substring(7)\n}\n"],"names":["pushStateEvent","popStateEvent","beforeUnloadEvent","beforeUnloadListener","event","preventDefault","returnValue","stopBlocking","removeEventListener","capture","createHistory","opts","location","getLocation","subscribers","Set","blockers","onUpdate","forEach","subscriber","tryNavigation","task","length","blocker","window","confirm","message","onBlocked","subscribe","cb","add","delete","push","path","state","assignKey","pushState","replace","replaceState","go","index","back","forward","createHref","str","block","payload","addEventListener","filter","b","flush","destroy","notify","key","createRandomKey","createBrowserHistory","getHref","pathname","search","hash","currentLocation","parseLocation","history","rollbackLocation","next","tracking","scheduled","untrack","fn","isPush","href","undefined","queueHistoryAction","type","Promise","resolve","then","onPushPop","originalPushState","originalReplaceState","n","res","apply","arguments","createHashHistory","substring","createMemoryHistory","initialEntries","entries","initialIndex","currentState","Math","min","hashIndex","indexOf","searchIndex","slice","random","toString"],"mappings":"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"}
@@ -4818,7 +4818,7 @@ var drawChart = (function (exports) {
4818
4818
  </script>
4819
4819
  <script>
4820
4820
  /*<!--*/
4821
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.production.js","children":[{"name":"packages/history/src/index.ts","uid":"fe4e-1"}]}],"isRoot":true},"nodeParts":{"fe4e-1":{"renderedLength":8900,"gzipLength":2605,"brotliLength":0,"metaUid":"fe4e-0"}},"nodeMetas":{"fe4e-0":{"id":"/packages/history/src/index.ts","moduleParts":{"index.production.js":"fe4e-1"},"imported":[],"importedBy":[],"isEntry":true}},"env":{"rollup":"4.6.1"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
4821
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.production.js","children":[{"name":"packages/history/src/index.ts","uid":"7ea9-1"}]}],"isRoot":true},"nodeParts":{"7ea9-1":{"renderedLength":9381,"gzipLength":2719,"brotliLength":0,"metaUid":"7ea9-0"}},"nodeMetas":{"7ea9-0":{"id":"/packages/history/src/index.ts","moduleParts":{"index.production.js":"7ea9-1"},"imported":[],"importedBy":[],"isEntry":true}},"env":{"rollup":"4.6.1"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
4822
4822
 
4823
4823
  const run = () => {
4824
4824
  const width = window.innerWidth;
@@ -8,7 +8,7 @@
8
8
  "children": [
9
9
  {
10
10
  "name": "packages/history/src/index.ts",
11
- "uid": "fe4e-3"
11
+ "uid": "7ea9-3"
12
12
  }
13
13
  ]
14
14
  }
@@ -16,18 +16,18 @@
16
16
  "isRoot": true
17
17
  },
18
18
  "nodeParts": {
19
- "fe4e-3": {
20
- "renderedLength": 8900,
21
- "gzipLength": 2605,
19
+ "7ea9-3": {
20
+ "renderedLength": 9381,
21
+ "gzipLength": 2719,
22
22
  "brotliLength": 0,
23
- "metaUid": "fe4e-2"
23
+ "metaUid": "7ea9-2"
24
24
  }
25
25
  },
26
26
  "nodeMetas": {
27
- "fe4e-2": {
27
+ "7ea9-2": {
28
28
  "id": "/packages/history/src/index.ts",
29
29
  "moduleParts": {
30
- "index.production.js": "fe4e-3"
30
+ "index.production.js": "7ea9-3"
31
31
  },
32
32
  "imported": [],
33
33
  "importedBy": [],
@@ -17,7 +17,7 @@ interface RouterHistory {
17
17
  back: () => void;
18
18
  forward: () => void;
19
19
  createHref: (href: string) => string;
20
- block: (blockerFn: BlockerFn) => () => void;
20
+ block: (message: string) => () => void;
21
21
  flush: () => void;
22
22
  destroy: () => void;
23
23
  notify: () => void;
@@ -34,7 +34,6 @@ interface ParsedPath {
34
34
  interface HistoryState {
35
35
  key: string;
36
36
  }
37
- type BlockerFn = (retry: () => void, cancel: () => void) => void;
38
37
  /**
39
38
  * Creates a history object that can be used to interact with the browser's
40
39
  * navigation. This is a lightweight API wrapping the browser's native methods.
@@ -35,26 +35,20 @@
35
35
  let location = opts.getLocation();
36
36
  let subscribers = new Set();
37
37
  let blockers = [];
38
- let queue = [];
39
38
  const onUpdate = () => {
40
39
  location = opts.getLocation();
41
40
  subscribers.forEach(subscriber => subscriber());
42
41
  };
43
- const tryUnblock = () => {
42
+ const tryNavigation = task => {
44
43
  if (blockers.length) {
45
- blockers[0]?.(tryUnblock, () => {
46
- blockers = [];
47
- stopBlocking();
48
- });
49
- return;
50
- }
51
- while (queue.length) {
52
- queue.shift()?.();
44
+ for (let blocker of blockers) {
45
+ if (!window.confirm(blocker.message)) {
46
+ opts.onBlocked?.(onUpdate);
47
+ return;
48
+ }
49
+ }
53
50
  }
54
- };
55
- const queueTask = task => {
56
- queue.push(task);
57
- tryUnblock();
51
+ task();
58
52
  };
59
53
  return {
60
54
  get location() {
@@ -68,41 +62,44 @@
68
62
  },
69
63
  push: (path, state) => {
70
64
  state = assignKey(state);
71
- queueTask(() => {
65
+ tryNavigation(() => {
72
66
  opts.pushState(path, state, onUpdate);
73
67
  });
74
68
  },
75
69
  replace: (path, state) => {
76
70
  state = assignKey(state);
77
- queueTask(() => {
71
+ tryNavigation(() => {
78
72
  opts.replaceState(path, state, onUpdate);
79
73
  });
80
74
  },
81
75
  go: index => {
82
- queueTask(() => {
76
+ tryNavigation(() => {
83
77
  opts.go(index);
84
78
  });
85
79
  },
86
80
  back: () => {
87
- queueTask(() => {
81
+ tryNavigation(() => {
88
82
  opts.back();
89
83
  });
90
84
  },
91
85
  forward: () => {
92
- queueTask(() => {
86
+ tryNavigation(() => {
93
87
  opts.forward();
94
88
  });
95
89
  },
96
90
  createHref: str => opts.createHref(str),
97
- block: cb => {
98
- blockers.push(cb);
91
+ block: message => {
92
+ const payload = {
93
+ message
94
+ };
95
+ blockers.push(payload);
99
96
  if (blockers.length === 1) {
100
97
  addEventListener(beforeUnloadEvent, beforeUnloadListener, {
101
98
  capture: true
102
99
  });
103
100
  }
104
101
  return () => {
105
- blockers = blockers.filter(b => b !== cb);
102
+ blockers = blockers.filter(b => b !== payload);
106
103
  if (!blockers.length) {
107
104
  stopBlocking();
108
105
  }
@@ -143,6 +140,7 @@
143
140
  const getHref = opts?.getHref ?? (() => `${window.location.pathname}${window.location.search}${window.location.hash}`);
144
141
  const createHref = opts?.createHref ?? (path => path);
145
142
  let currentLocation = parseLocation(getHref(), window.history.state);
143
+ let rollbackLocation;
146
144
  const getLocation = () => currentLocation;
147
145
  let next;
148
146
 
@@ -173,12 +171,16 @@
173
171
  // Reset the nextIsPush flag and clear the scheduled update
174
172
  next = undefined;
175
173
  scheduled = undefined;
174
+ rollbackLocation = undefined;
176
175
  });
177
176
  };
178
177
 
179
178
  // This function queues up a call to update the browser history
180
179
  const queueHistoryAction = (type, path, state, onUpdate) => {
181
180
  const href = createHref(path);
181
+ if (!scheduled) {
182
+ rollbackLocation = currentLocation;
183
+ }
182
184
 
183
185
  // Update the location in memory
184
186
  currentLocation = parseLocation(href, state);
@@ -189,6 +191,7 @@
189
191
  state,
190
192
  isPush: next?.isPush || type === 'push'
191
193
  };
194
+
192
195
  // Notify subscribers
193
196
  onUpdate();
194
197
  if (!scheduled) {
@@ -216,6 +219,15 @@
216
219
  window.history.replaceState = originalReplaceState;
217
220
  window.removeEventListener(pushStateEvent, onPushPop);
218
221
  window.removeEventListener(popStateEvent, onPushPop);
222
+ },
223
+ onBlocked: onUpdate => {
224
+ // If a navigation is blocked, we need to rollback the location
225
+ // that we optimistically updated in memory.
226
+ if (rollbackLocation && currentLocation !== rollbackLocation) {
227
+ currentLocation = rollbackLocation;
228
+ // Notify subscribers
229
+ onUpdate();
230
+ }
219
231
  }
220
232
  });
221
233
  window.addEventListener(pushStateEvent, onPushPop);
@@ -1 +1 @@
1
- {"version":3,"file":"index.development.js","sources":["../../src/index.ts"],"sourcesContent":["// While the public API was clearly inspired by the \"history\" npm package,\n// This implementation attempts to be more lightweight by\n// making assumptions about the way TanStack Router works\n\nexport interface RouterHistory {\n location: HistoryLocation\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any) => void\n replace: (path: string, state?: any) => void\n go: (index: number) => void\n back: () => void\n forward: () => void\n createHref: (href: string) => string\n block: (blockerFn: BlockerFn) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n}\n\nexport interface HistoryLocation extends ParsedPath {\n state: HistoryState\n}\n\nexport interface ParsedPath {\n href: string\n pathname: string\n search: string\n hash: string\n}\n\nexport interface HistoryState {\n key: string\n}\n\ntype BlockerFn = (retry: () => void, cancel: () => void) => void\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-ignore\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nfunction createHistory(opts: {\n getLocation: () => HistoryLocation\n pushState: (path: string, state: any, onUpdate: () => void) => void\n replaceState: (path: string, state: any, onUpdate: () => void) => void\n go: (n: number) => void\n back: () => void\n forward: () => void\n createHref: (path: string) => string\n flush?: () => void\n destroy?: () => void\n}): RouterHistory {\n let location = opts.getLocation()\n let subscribers = new Set<() => void>()\n let blockers: BlockerFn[] = []\n let queue: (() => void)[] = []\n\n const onUpdate = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryUnblock = () => {\n if (blockers.length) {\n blockers[0]?.(tryUnblock, () => {\n blockers = []\n stopBlocking()\n })\n return\n }\n\n while (queue.length) {\n queue.shift()?.()\n }\n }\n\n const queueTask = (task: () => void) => {\n queue.push(task)\n tryUnblock()\n }\n\n return {\n get location() {\n return location\n },\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path: string, state: any) => {\n state = assignKey(state)\n queueTask(() => {\n opts.pushState(path, state, onUpdate)\n })\n },\n replace: (path: string, state: any) => {\n state = assignKey(state)\n queueTask(() => {\n opts.replaceState(path, state, onUpdate)\n })\n },\n go: (index) => {\n queueTask(() => {\n opts.go(index)\n })\n },\n back: () => {\n queueTask(() => {\n opts.back()\n })\n },\n forward: () => {\n queueTask(() => {\n opts.forward()\n })\n },\n createHref: (str) => opts.createHref(str),\n block: (cb) => {\n blockers.push(cb)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== cb)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify: onUpdate,\n }\n}\n\nfunction assignKey(state: HistoryState) {\n if (!state) {\n state = {} as HistoryState\n }\n return {\n ...state,\n key: createRandomKey(),\n }\n}\n\n/**\n * Creates a history object that can be used to interact with the browser's\n * navigation. This is a lightweight API wrapping the browser's native methods.\n * It is designed to work with TanStack Router, but could be used as a standalone API as well.\n * IMPORTANT: This API implements history throttling via a microtask to prevent\n * excessive calls to the history API. In some browsers, calling history.pushState or\n * history.replaceState in quick succession can cause the browser to ignore subsequent\n * calls. This API smooths out those differences and ensures that your application\n * state will *eventually* match the browser state. In most cases, this is not a problem,\n * but if you need to ensure that the browser state is up to date, you can use the\n * `history.flush` method to immediately flush all pending state changes to the browser URL.\n * @param opts\n * @param opts.getHref A function that returns the current href (path + search + hash)\n * @param opts.createHref A function that takes a path and returns a href (path + search + hash)\n * @returns A history instance\n */\nexport function createBrowserHistory(opts?: {\n getHref?: () => string\n createHref?: (path: string) => string\n}): RouterHistory {\n const getHref =\n opts?.getHref ??\n (() =>\n `${window.location.pathname}${window.location.search}${window.location.hash}`)\n\n const createHref = opts?.createHref ?? ((path) => path)\n\n let currentLocation = parseLocation(getHref(), window.history.state)\n\n const getLocation = () => currentLocation\n\n let next:\n | undefined\n | {\n // This is the latest location that we were attempting to push/replace\n href: string\n // This is the latest state that we were attempting to push/replace\n state: any\n // This is the latest type that we were attempting to push/replace\n isPush: boolean\n }\n\n // Because we are proactively updating the location\n // in memory before actually updating the browser history,\n // we need to track when we are doing this so we don't\n // notify subscribers twice on the last update.\n let tracking = true\n\n // We need to track the current scheduled update to prevent\n // multiple updates from being scheduled at the same time.\n let scheduled: Promise<void> | undefined\n\n // This function is a wrapper to prevent any of the callback's\n // side effects from causing a subscriber notification\n const untrack = (fn: () => void) => {\n tracking = false\n fn()\n tracking = true\n }\n\n // This function flushes the next update to the browser history\n const flush = () => {\n // Do not notify subscribers about this push/replace call\n untrack(() => {\n if (!next) return\n window.history[next.isPush ? 'pushState' : 'replaceState'](\n next.state,\n '',\n next.href,\n )\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n })\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n path: string,\n state: any,\n onUpdate: () => void,\n ) => {\n const href = createHref(path)\n\n // Update the location in memory\n currentLocation = parseLocation(href, state)\n\n // Keep track of the next location we need to flush to the URL\n next = {\n href,\n state,\n isPush: next?.isPush || type === 'push',\n }\n // Notify subscribers\n onUpdate()\n\n if (!scheduled) {\n // Schedule an update to the browser history\n scheduled = Promise.resolve().then(() => flush())\n }\n }\n\n const onPushPop = () => {\n currentLocation = parseLocation(getHref(), window.history.state)\n history.notify()\n }\n\n var originalPushState = window.history.pushState\n var originalReplaceState = window.history.replaceState\n\n const history = createHistory({\n getLocation,\n pushState: (path, state, onUpdate) =>\n queueHistoryAction('push', path, state, onUpdate),\n replaceState: (path, state, onUpdate) =>\n queueHistoryAction('replace', path, state, onUpdate),\n back: () => window.history.back(),\n forward: () => window.history.forward(),\n go: (n) => window.history.go(n),\n createHref: (path) => createHref(path),\n flush,\n destroy: () => {\n window.history.pushState = originalPushState\n window.history.replaceState = originalReplaceState\n window.removeEventListener(pushStateEvent, onPushPop)\n window.removeEventListener(popStateEvent, onPushPop)\n },\n })\n\n window.addEventListener(pushStateEvent, onPushPop)\n window.addEventListener(popStateEvent, onPushPop)\n\n window.history.pushState = function () {\n let res = originalPushState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n window.history.replaceState = function () {\n let res = originalReplaceState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(): RouterHistory {\n return createBrowserHistory({\n getHref: () => window.location.hash.substring(1),\n createHref: (path) => `#${path}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: string[]\n initialIndex?: number\n } = {\n initialEntries: ['/'],\n },\n): RouterHistory {\n const entries = opts.initialEntries\n let index = opts.initialIndex ?? entries.length - 1\n let currentState = {\n key: createRandomKey(),\n } as HistoryState\n\n const getLocation = () => parseLocation(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n pushState: (path, state) => {\n currentState = state\n entries.push(path)\n index++\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n index--\n },\n forward: () => {\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => window.history.go(n),\n createHref: (path) => path,\n })\n}\n\nfunction parseLocation(href: string, state: HistoryState): HistoryLocation {\n let hashIndex = href.indexOf('#')\n let searchIndex = href.indexOf('?')\n\n return {\n href,\n pathname: href.substring(\n 0,\n hashIndex > 0\n ? searchIndex > 0\n ? Math.min(hashIndex, searchIndex)\n : hashIndex\n : searchIndex > 0\n ? searchIndex\n : href.length,\n ),\n hash: hashIndex > -1 ? href.substring(hashIndex) : '',\n search:\n searchIndex > -1\n ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex)\n : '',\n state: state || {},\n }\n}\n\n// Thanks co-pilot!\nfunction createRandomKey() {\n return (Math.random() + 1).toString(36).substring(7)\n}\n"],"names":["pushStateEvent","popStateEvent","beforeUnloadEvent","beforeUnloadListener","event","preventDefault","returnValue","stopBlocking","removeEventListener","capture","createHistory","opts","location","getLocation","subscribers","Set","blockers","queue","onUpdate","forEach","subscriber","tryUnblock","length","shift","queueTask","task","push","subscribe","cb","add","delete","path","state","assignKey","pushState","replace","replaceState","go","index","back","forward","createHref","str","block","addEventListener","filter","b","flush","destroy","notify","key","createRandomKey","createBrowserHistory","getHref","window","pathname","search","hash","currentLocation","parseLocation","history","next","tracking","scheduled","untrack","fn","isPush","href","undefined","queueHistoryAction","type","Promise","resolve","then","onPushPop","originalPushState","originalReplaceState","n","res","apply","arguments","createHashHistory","substring","createMemoryHistory","initialEntries","entries","initialIndex","currentState","Math","min","hashIndex","indexOf","searchIndex","slice","random","toString"],"mappings":"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"}
1
+ {"version":3,"file":"index.development.js","sources":["../../src/index.ts"],"sourcesContent":["// While the public API was clearly inspired by the \"history\" npm package,\n// This implementation attempts to be more lightweight by\n// making assumptions about the way TanStack Router works\n\nexport interface RouterHistory {\n location: HistoryLocation\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any) => void\n replace: (path: string, state?: any) => void\n go: (index: number) => void\n back: () => void\n forward: () => void\n createHref: (href: string) => string\n block: (message: string) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n}\n\nexport interface HistoryLocation extends ParsedPath {\n state: HistoryState\n}\n\nexport interface ParsedPath {\n href: string\n pathname: string\n search: string\n hash: string\n}\n\nexport interface HistoryState {\n key: string\n}\n\ntype Blocker = {\n message: string\n}\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-ignore\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nfunction createHistory(opts: {\n getLocation: () => HistoryLocation\n pushState: (path: string, state: any, onUpdate: () => void) => void\n replaceState: (path: string, state: any, onUpdate: () => void) => void\n go: (n: number) => void\n back: () => void\n forward: () => void\n createHref: (path: string) => string\n flush?: () => void\n destroy?: () => void\n onBlocked?: (onUpdate: () => void) => void\n}): RouterHistory {\n let location = opts.getLocation()\n let subscribers = new Set<() => void>()\n let blockers: Blocker[] = []\n\n const onUpdate = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryNavigation = (task: () => void) => {\n if (blockers.length) {\n for (let blocker of blockers) {\n if (!window.confirm(blocker.message)) {\n opts.onBlocked?.(onUpdate)\n return\n }\n }\n }\n\n task()\n }\n\n return {\n get location() {\n return location\n },\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path: string, state: any) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.pushState(path, state, onUpdate)\n })\n },\n replace: (path: string, state: any) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.replaceState(path, state, onUpdate)\n })\n },\n go: (index) => {\n tryNavigation(() => {\n opts.go(index)\n })\n },\n back: () => {\n tryNavigation(() => {\n opts.back()\n })\n },\n forward: () => {\n tryNavigation(() => {\n opts.forward()\n })\n },\n createHref: (str) => opts.createHref(str),\n block: (message) => {\n const payload: Blocker = {\n message,\n }\n\n blockers.push(payload)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== payload)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify: onUpdate,\n }\n}\n\nfunction assignKey(state: HistoryState) {\n if (!state) {\n state = {} as HistoryState\n }\n return {\n ...state,\n key: createRandomKey(),\n }\n}\n\n/**\n * Creates a history object that can be used to interact with the browser's\n * navigation. This is a lightweight API wrapping the browser's native methods.\n * It is designed to work with TanStack Router, but could be used as a standalone API as well.\n * IMPORTANT: This API implements history throttling via a microtask to prevent\n * excessive calls to the history API. In some browsers, calling history.pushState or\n * history.replaceState in quick succession can cause the browser to ignore subsequent\n * calls. This API smooths out those differences and ensures that your application\n * state will *eventually* match the browser state. In most cases, this is not a problem,\n * but if you need to ensure that the browser state is up to date, you can use the\n * `history.flush` method to immediately flush all pending state changes to the browser URL.\n * @param opts\n * @param opts.getHref A function that returns the current href (path + search + hash)\n * @param opts.createHref A function that takes a path and returns a href (path + search + hash)\n * @returns A history instance\n */\nexport function createBrowserHistory(opts?: {\n getHref?: () => string\n createHref?: (path: string) => string\n}): RouterHistory {\n const getHref =\n opts?.getHref ??\n (() =>\n `${window.location.pathname}${window.location.search}${window.location.hash}`)\n\n const createHref = opts?.createHref ?? ((path) => path)\n\n let currentLocation = parseLocation(getHref(), window.history.state)\n let rollbackLocation: HistoryLocation | undefined\n\n const getLocation = () => currentLocation\n\n let next:\n | undefined\n | {\n // This is the latest location that we were attempting to push/replace\n href: string\n // This is the latest state that we were attempting to push/replace\n state: any\n // This is the latest type that we were attempting to push/replace\n isPush: boolean\n }\n\n // Because we are proactively updating the location\n // in memory before actually updating the browser history,\n // we need to track when we are doing this so we don't\n // notify subscribers twice on the last update.\n let tracking = true\n\n // We need to track the current scheduled update to prevent\n // multiple updates from being scheduled at the same time.\n let scheduled: Promise<void> | undefined\n\n // This function is a wrapper to prevent any of the callback's\n // side effects from causing a subscriber notification\n const untrack = (fn: () => void) => {\n tracking = false\n fn()\n tracking = true\n }\n\n // This function flushes the next update to the browser history\n const flush = () => {\n // Do not notify subscribers about this push/replace call\n untrack(() => {\n if (!next) return\n window.history[next.isPush ? 'pushState' : 'replaceState'](\n next.state,\n '',\n next.href,\n )\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n rollbackLocation = undefined\n })\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n path: string,\n state: any,\n onUpdate: () => void,\n ) => {\n const href = createHref(path)\n\n if (!scheduled) {\n rollbackLocation = currentLocation\n }\n\n // Update the location in memory\n currentLocation = parseLocation(href, state)\n\n // Keep track of the next location we need to flush to the URL\n next = {\n href,\n state,\n isPush: next?.isPush || type === 'push',\n }\n\n // Notify subscribers\n onUpdate()\n\n if (!scheduled) {\n // Schedule an update to the browser history\n scheduled = Promise.resolve().then(() => flush())\n }\n }\n\n const onPushPop = () => {\n currentLocation = parseLocation(getHref(), window.history.state)\n history.notify()\n }\n\n var originalPushState = window.history.pushState\n var originalReplaceState = window.history.replaceState\n\n const history = createHistory({\n getLocation,\n pushState: (path, state, onUpdate) =>\n queueHistoryAction('push', path, state, onUpdate),\n replaceState: (path, state, onUpdate) =>\n queueHistoryAction('replace', path, state, onUpdate),\n back: () => window.history.back(),\n forward: () => window.history.forward(),\n go: (n) => window.history.go(n),\n createHref: (path) => createHref(path),\n flush,\n destroy: () => {\n window.history.pushState = originalPushState\n window.history.replaceState = originalReplaceState\n window.removeEventListener(pushStateEvent, onPushPop)\n window.removeEventListener(popStateEvent, onPushPop)\n },\n onBlocked: (onUpdate) => {\n // If a navigation is blocked, we need to rollback the location\n // that we optimistically updated in memory.\n if (rollbackLocation && currentLocation !== rollbackLocation) {\n currentLocation = rollbackLocation\n // Notify subscribers\n onUpdate()\n }\n },\n })\n\n window.addEventListener(pushStateEvent, onPushPop)\n window.addEventListener(popStateEvent, onPushPop)\n\n window.history.pushState = function () {\n let res = originalPushState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n window.history.replaceState = function () {\n let res = originalReplaceState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(): RouterHistory {\n return createBrowserHistory({\n getHref: () => window.location.hash.substring(1),\n createHref: (path) => `#${path}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: string[]\n initialIndex?: number\n } = {\n initialEntries: ['/'],\n },\n): RouterHistory {\n const entries = opts.initialEntries\n let index = opts.initialIndex ?? entries.length - 1\n let currentState = {\n key: createRandomKey(),\n } as HistoryState\n\n const getLocation = () => parseLocation(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n pushState: (path, state) => {\n currentState = state\n entries.push(path)\n index++\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n index--\n },\n forward: () => {\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => window.history.go(n),\n createHref: (path) => path,\n })\n}\n\nfunction parseLocation(href: string, state: HistoryState): HistoryLocation {\n let hashIndex = href.indexOf('#')\n let searchIndex = href.indexOf('?')\n\n return {\n href,\n pathname: href.substring(\n 0,\n hashIndex > 0\n ? searchIndex > 0\n ? Math.min(hashIndex, searchIndex)\n : hashIndex\n : searchIndex > 0\n ? searchIndex\n : href.length,\n ),\n hash: hashIndex > -1 ? href.substring(hashIndex) : '',\n search:\n searchIndex > -1\n ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex)\n : '',\n state: state || {},\n }\n}\n\n// Thanks co-pilot!\nfunction createRandomKey() {\n return (Math.random() + 1).toString(36).substring(7)\n}\n"],"names":["pushStateEvent","popStateEvent","beforeUnloadEvent","beforeUnloadListener","event","preventDefault","returnValue","stopBlocking","removeEventListener","capture","createHistory","opts","location","getLocation","subscribers","Set","blockers","onUpdate","forEach","subscriber","tryNavigation","task","length","blocker","window","confirm","message","onBlocked","subscribe","cb","add","delete","push","path","state","assignKey","pushState","replace","replaceState","go","index","back","forward","createHref","str","block","payload","addEventListener","filter","b","flush","destroy","notify","key","createRandomKey","createBrowserHistory","getHref","pathname","search","hash","currentLocation","parseLocation","history","rollbackLocation","next","tracking","scheduled","untrack","fn","isPush","href","undefined","queueHistoryAction","type","Promise","resolve","then","onPushPop","originalPushState","originalReplaceState","n","res","apply","arguments","createHashHistory","substring","createMemoryHistory","initialEntries","entries","initialIndex","currentState","Math","min","hashIndex","indexOf","searchIndex","slice","random","toString"],"mappings":"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"}
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).TanStackHistory={})}(this,(function(t){"use strict";const e="pushstate",n="popstate",o="beforeunload",r=t=>(t.preventDefault(),t.returnValue=""),i=()=>{removeEventListener(o,r,{capture:!0})};function s(t){let e=t.getLocation(),n=new Set,s=[],h=[];const c=()=>{e=t.getLocation(),n.forEach((t=>t()))},d=()=>{if(s.length)s[0]?.(d,(()=>{s=[],i()}));else for(;h.length;)h.shift()?.()},u=t=>{h.push(t),d()};return{get location(){return e},subscribe:t=>(n.add(t),()=>{n.delete(t)}),push:(e,n)=>{n=a(n),u((()=>{t.pushState(e,n,c)}))},replace:(e,n)=>{n=a(n),u((()=>{t.replaceState(e,n,c)}))},go:e=>{u((()=>{t.go(e)}))},back:()=>{u((()=>{t.back()}))},forward:()=>{u((()=>{t.forward()}))},createHref:e=>t.createHref(e),block:t=>(s.push(t),1===s.length&&addEventListener(o,r,{capture:!0}),()=>{s=s.filter((e=>e!==t)),s.length||i()}),flush:()=>t.flush?.(),destroy:()=>t.destroy?.(),notify:c}}function a(t){return t||(t={}),{...t,key:d()}}function h(t){const o=t?.getHref??(()=>`${window.location.pathname}${window.location.search}${window.location.hash}`),r=t?.createHref??(t=>t);let i=c(o(),window.history.state);let a,h,d=!0;const u=()=>{d=!1,(()=>{a&&(window.history[a.isPush?"pushState":"replaceState"](a.state,"",a.href),a=void 0,h=void 0)})(),d=!0},f=(t,e,n,o)=>{const s=r(e);i=c(s,n),a={href:s,state:n,isPush:a?.isPush||"push"===t},o(),h||(h=Promise.resolve().then((()=>u())))},w=()=>{i=c(o(),window.history.state),y.notify()};var l=window.history.pushState,p=window.history.replaceState;const y=s({getLocation:()=>i,pushState:(t,e,n)=>f("push",t,e,n),replaceState:(t,e,n)=>f("replace",t,e,n),back:()=>window.history.back(),forward:()=>window.history.forward(),go:t=>window.history.go(t),createHref:t=>r(t),flush:u,destroy:()=>{window.history.pushState=l,window.history.replaceState=p,window.removeEventListener(e,w),window.removeEventListener(n,w)}});return window.addEventListener(e,w),window.addEventListener(n,w),window.history.pushState=function(){let t=l.apply(window.history,arguments);return d&&y.notify(),t},window.history.replaceState=function(){let t=p.apply(window.history,arguments);return d&&y.notify(),t},y}function c(t,e){let n=t.indexOf("#"),o=t.indexOf("?");return{href:t,pathname:t.substring(0,n>0?o>0?Math.min(n,o):n:o>0?o:t.length),hash:n>-1?t.substring(n):"",search:o>-1?t.slice(o,-1===n?void 0:n):"",state:e||{}}}function d(){return(Math.random()+1).toString(36).substring(7)}t.createBrowserHistory=h,t.createHashHistory=function(){return h({getHref:()=>window.location.hash.substring(1),createHref:t=>`#${t}`})},t.createMemoryHistory=function(t={initialEntries:["/"]}){const e=t.initialEntries;let n=t.initialIndex??e.length-1,o={key:d()};return s({getLocation:()=>c(e[n],o),pushState:(t,r)=>{o=r,e.push(t),n++},replaceState:(t,r)=>{o=r,e[n]=t},back:()=>{n--},forward:()=>{n=Math.min(n+1,e.length-1)},go:t=>window.history.go(t),createHref:t=>t})}}));
11
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).TanStackHistory={})}(this,(function(e){"use strict";const t="pushstate",o="popstate",n="beforeunload",r=e=>(e.preventDefault(),e.returnValue=""),i=()=>{removeEventListener(n,r,{capture:!0})};function s(e){let t=e.getLocation(),o=new Set,s=[];const c=()=>{t=e.getLocation(),o.forEach((e=>e()))},d=t=>{if(s.length)for(let t of s)if(!window.confirm(t.message))return void e.onBlocked?.(c);t()};return{get location(){return t},subscribe:e=>(o.add(e),()=>{o.delete(e)}),push:(t,o)=>{o=a(o),d((()=>{e.pushState(t,o,c)}))},replace:(t,o)=>{o=a(o),d((()=>{e.replaceState(t,o,c)}))},go:t=>{d((()=>{e.go(t)}))},back:()=>{d((()=>{e.back()}))},forward:()=>{d((()=>{e.forward()}))},createHref:t=>e.createHref(t),block:e=>{const t={message:e};return s.push(t),1===s.length&&addEventListener(n,r,{capture:!0}),()=>{s=s.filter((e=>e!==t)),s.length||i()}},flush:()=>e.flush?.(),destroy:()=>e.destroy?.(),notify:c}}function a(e){return e||(e={}),{...e,key:h()}}function c(e){const n=e?.getHref??(()=>`${window.location.pathname}${window.location.search}${window.location.hash}`),r=e?.createHref??(e=>e);let i,a=d(n(),window.history.state);let c,h,u=!0;const f=()=>{u=!1,(()=>{c&&(window.history[c.isPush?"pushState":"replaceState"](c.state,"",c.href),c=void 0,h=void 0,i=void 0)})(),u=!0},w=(e,t,o,n)=>{const s=r(t);h||(i=a),a=d(s,o),c={href:s,state:o,isPush:c?.isPush||"push"===e},n(),h||(h=Promise.resolve().then((()=>f())))},l=()=>{a=d(n(),window.history.state),g.notify()};var p=window.history.pushState,y=window.history.replaceState;const g=s({getLocation:()=>a,pushState:(e,t,o)=>w("push",e,t,o),replaceState:(e,t,o)=>w("replace",e,t,o),back:()=>window.history.back(),forward:()=>window.history.forward(),go:e=>window.history.go(e),createHref:e=>r(e),flush:f,destroy:()=>{window.history.pushState=p,window.history.replaceState=y,window.removeEventListener(t,l),window.removeEventListener(o,l)},onBlocked:e=>{i&&a!==i&&(a=i,e())}});return window.addEventListener(t,l),window.addEventListener(o,l),window.history.pushState=function(){let e=p.apply(window.history,arguments);return u&&g.notify(),e},window.history.replaceState=function(){let e=y.apply(window.history,arguments);return u&&g.notify(),e},g}function d(e,t){let o=e.indexOf("#"),n=e.indexOf("?");return{href:e,pathname:e.substring(0,o>0?n>0?Math.min(o,n):o:n>0?n:e.length),hash:o>-1?e.substring(o):"",search:n>-1?e.slice(n,-1===o?void 0:o):"",state:t||{}}}function h(){return(Math.random()+1).toString(36).substring(7)}e.createBrowserHistory=c,e.createHashHistory=function(){return c({getHref:()=>window.location.hash.substring(1),createHref:e=>`#${e}`})},e.createMemoryHistory=function(e={initialEntries:["/"]}){const t=e.initialEntries;let o=e.initialIndex??t.length-1,n={key:h()};return s({getLocation:()=>d(t[o],n),pushState:(e,r)=>{n=r,t.push(e),o++},replaceState:(e,r)=>{n=r,t[o]=e},back:()=>{o--},forward:()=>{o=Math.min(o+1,t.length-1)},go:e=>window.history.go(e),createHref:e=>e})}}));
12
12
  //# sourceMappingURL=index.production.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.production.js","sources":["../../src/index.ts"],"sourcesContent":["// While the public API was clearly inspired by the \"history\" npm package,\n// This implementation attempts to be more lightweight by\n// making assumptions about the way TanStack Router works\n\nexport interface RouterHistory {\n location: HistoryLocation\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any) => void\n replace: (path: string, state?: any) => void\n go: (index: number) => void\n back: () => void\n forward: () => void\n createHref: (href: string) => string\n block: (blockerFn: BlockerFn) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n}\n\nexport interface HistoryLocation extends ParsedPath {\n state: HistoryState\n}\n\nexport interface ParsedPath {\n href: string\n pathname: string\n search: string\n hash: string\n}\n\nexport interface HistoryState {\n key: string\n}\n\ntype BlockerFn = (retry: () => void, cancel: () => void) => void\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-ignore\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nfunction createHistory(opts: {\n getLocation: () => HistoryLocation\n pushState: (path: string, state: any, onUpdate: () => void) => void\n replaceState: (path: string, state: any, onUpdate: () => void) => void\n go: (n: number) => void\n back: () => void\n forward: () => void\n createHref: (path: string) => string\n flush?: () => void\n destroy?: () => void\n}): RouterHistory {\n let location = opts.getLocation()\n let subscribers = new Set<() => void>()\n let blockers: BlockerFn[] = []\n let queue: (() => void)[] = []\n\n const onUpdate = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryUnblock = () => {\n if (blockers.length) {\n blockers[0]?.(tryUnblock, () => {\n blockers = []\n stopBlocking()\n })\n return\n }\n\n while (queue.length) {\n queue.shift()?.()\n }\n }\n\n const queueTask = (task: () => void) => {\n queue.push(task)\n tryUnblock()\n }\n\n return {\n get location() {\n return location\n },\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path: string, state: any) => {\n state = assignKey(state)\n queueTask(() => {\n opts.pushState(path, state, onUpdate)\n })\n },\n replace: (path: string, state: any) => {\n state = assignKey(state)\n queueTask(() => {\n opts.replaceState(path, state, onUpdate)\n })\n },\n go: (index) => {\n queueTask(() => {\n opts.go(index)\n })\n },\n back: () => {\n queueTask(() => {\n opts.back()\n })\n },\n forward: () => {\n queueTask(() => {\n opts.forward()\n })\n },\n createHref: (str) => opts.createHref(str),\n block: (cb) => {\n blockers.push(cb)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== cb)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify: onUpdate,\n }\n}\n\nfunction assignKey(state: HistoryState) {\n if (!state) {\n state = {} as HistoryState\n }\n return {\n ...state,\n key: createRandomKey(),\n }\n}\n\n/**\n * Creates a history object that can be used to interact with the browser's\n * navigation. This is a lightweight API wrapping the browser's native methods.\n * It is designed to work with TanStack Router, but could be used as a standalone API as well.\n * IMPORTANT: This API implements history throttling via a microtask to prevent\n * excessive calls to the history API. In some browsers, calling history.pushState or\n * history.replaceState in quick succession can cause the browser to ignore subsequent\n * calls. This API smooths out those differences and ensures that your application\n * state will *eventually* match the browser state. In most cases, this is not a problem,\n * but if you need to ensure that the browser state is up to date, you can use the\n * `history.flush` method to immediately flush all pending state changes to the browser URL.\n * @param opts\n * @param opts.getHref A function that returns the current href (path + search + hash)\n * @param opts.createHref A function that takes a path and returns a href (path + search + hash)\n * @returns A history instance\n */\nexport function createBrowserHistory(opts?: {\n getHref?: () => string\n createHref?: (path: string) => string\n}): RouterHistory {\n const getHref =\n opts?.getHref ??\n (() =>\n `${window.location.pathname}${window.location.search}${window.location.hash}`)\n\n const createHref = opts?.createHref ?? ((path) => path)\n\n let currentLocation = parseLocation(getHref(), window.history.state)\n\n const getLocation = () => currentLocation\n\n let next:\n | undefined\n | {\n // This is the latest location that we were attempting to push/replace\n href: string\n // This is the latest state that we were attempting to push/replace\n state: any\n // This is the latest type that we were attempting to push/replace\n isPush: boolean\n }\n\n // Because we are proactively updating the location\n // in memory before actually updating the browser history,\n // we need to track when we are doing this so we don't\n // notify subscribers twice on the last update.\n let tracking = true\n\n // We need to track the current scheduled update to prevent\n // multiple updates from being scheduled at the same time.\n let scheduled: Promise<void> | undefined\n\n // This function is a wrapper to prevent any of the callback's\n // side effects from causing a subscriber notification\n const untrack = (fn: () => void) => {\n tracking = false\n fn()\n tracking = true\n }\n\n // This function flushes the next update to the browser history\n const flush = () => {\n // Do not notify subscribers about this push/replace call\n untrack(() => {\n if (!next) return\n window.history[next.isPush ? 'pushState' : 'replaceState'](\n next.state,\n '',\n next.href,\n )\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n })\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n path: string,\n state: any,\n onUpdate: () => void,\n ) => {\n const href = createHref(path)\n\n // Update the location in memory\n currentLocation = parseLocation(href, state)\n\n // Keep track of the next location we need to flush to the URL\n next = {\n href,\n state,\n isPush: next?.isPush || type === 'push',\n }\n // Notify subscribers\n onUpdate()\n\n if (!scheduled) {\n // Schedule an update to the browser history\n scheduled = Promise.resolve().then(() => flush())\n }\n }\n\n const onPushPop = () => {\n currentLocation = parseLocation(getHref(), window.history.state)\n history.notify()\n }\n\n var originalPushState = window.history.pushState\n var originalReplaceState = window.history.replaceState\n\n const history = createHistory({\n getLocation,\n pushState: (path, state, onUpdate) =>\n queueHistoryAction('push', path, state, onUpdate),\n replaceState: (path, state, onUpdate) =>\n queueHistoryAction('replace', path, state, onUpdate),\n back: () => window.history.back(),\n forward: () => window.history.forward(),\n go: (n) => window.history.go(n),\n createHref: (path) => createHref(path),\n flush,\n destroy: () => {\n window.history.pushState = originalPushState\n window.history.replaceState = originalReplaceState\n window.removeEventListener(pushStateEvent, onPushPop)\n window.removeEventListener(popStateEvent, onPushPop)\n },\n })\n\n window.addEventListener(pushStateEvent, onPushPop)\n window.addEventListener(popStateEvent, onPushPop)\n\n window.history.pushState = function () {\n let res = originalPushState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n window.history.replaceState = function () {\n let res = originalReplaceState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(): RouterHistory {\n return createBrowserHistory({\n getHref: () => window.location.hash.substring(1),\n createHref: (path) => `#${path}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: string[]\n initialIndex?: number\n } = {\n initialEntries: ['/'],\n },\n): RouterHistory {\n const entries = opts.initialEntries\n let index = opts.initialIndex ?? entries.length - 1\n let currentState = {\n key: createRandomKey(),\n } as HistoryState\n\n const getLocation = () => parseLocation(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n pushState: (path, state) => {\n currentState = state\n entries.push(path)\n index++\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n index--\n },\n forward: () => {\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => window.history.go(n),\n createHref: (path) => path,\n })\n}\n\nfunction parseLocation(href: string, state: HistoryState): HistoryLocation {\n let hashIndex = href.indexOf('#')\n let searchIndex = href.indexOf('?')\n\n return {\n href,\n pathname: href.substring(\n 0,\n hashIndex > 0\n ? searchIndex > 0\n ? Math.min(hashIndex, searchIndex)\n : hashIndex\n : searchIndex > 0\n ? searchIndex\n : href.length,\n ),\n hash: hashIndex > -1 ? href.substring(hashIndex) : '',\n search:\n searchIndex > -1\n ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex)\n : '',\n state: state || {},\n }\n}\n\n// Thanks co-pilot!\nfunction createRandomKey() {\n return (Math.random() + 1).toString(36).substring(7)\n}\n"],"names":["pushStateEvent","popStateEvent","beforeUnloadEvent","beforeUnloadListener","event","preventDefault","returnValue","stopBlocking","removeEventListener","capture","createHistory","opts","location","getLocation","subscribers","Set","blockers","queue","onUpdate","forEach","subscriber","tryUnblock","length","shift","queueTask","task","push","subscribe","cb","add","delete","path","state","assignKey","pushState","replace","replaceState","go","index","back","forward","createHref","str","block","addEventListener","filter","b","flush","destroy","notify","key","createRandomKey","createBrowserHistory","getHref","window","pathname","search","hash","currentLocation","parseLocation","history","next","scheduled","tracking","isPush","href","undefined","fn","queueHistoryAction","type","Promise","resolve","then","onPushPop","originalPushState","originalReplaceState","n","res","apply","arguments","hashIndex","indexOf","searchIndex","substring","Math","min","slice","random","toString","initialEntries","entries","initialIndex","currentState"],"mappings":"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"}
1
+ {"version":3,"file":"index.production.js","sources":["../../src/index.ts"],"sourcesContent":["// While the public API was clearly inspired by the \"history\" npm package,\n// This implementation attempts to be more lightweight by\n// making assumptions about the way TanStack Router works\n\nexport interface RouterHistory {\n location: HistoryLocation\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any) => void\n replace: (path: string, state?: any) => void\n go: (index: number) => void\n back: () => void\n forward: () => void\n createHref: (href: string) => string\n block: (message: string) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n}\n\nexport interface HistoryLocation extends ParsedPath {\n state: HistoryState\n}\n\nexport interface ParsedPath {\n href: string\n pathname: string\n search: string\n hash: string\n}\n\nexport interface HistoryState {\n key: string\n}\n\ntype Blocker = {\n message: string\n}\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-ignore\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nfunction createHistory(opts: {\n getLocation: () => HistoryLocation\n pushState: (path: string, state: any, onUpdate: () => void) => void\n replaceState: (path: string, state: any, onUpdate: () => void) => void\n go: (n: number) => void\n back: () => void\n forward: () => void\n createHref: (path: string) => string\n flush?: () => void\n destroy?: () => void\n onBlocked?: (onUpdate: () => void) => void\n}): RouterHistory {\n let location = opts.getLocation()\n let subscribers = new Set<() => void>()\n let blockers: Blocker[] = []\n\n const onUpdate = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryNavigation = (task: () => void) => {\n if (blockers.length) {\n for (let blocker of blockers) {\n if (!window.confirm(blocker.message)) {\n opts.onBlocked?.(onUpdate)\n return\n }\n }\n }\n\n task()\n }\n\n return {\n get location() {\n return location\n },\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path: string, state: any) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.pushState(path, state, onUpdate)\n })\n },\n replace: (path: string, state: any) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.replaceState(path, state, onUpdate)\n })\n },\n go: (index) => {\n tryNavigation(() => {\n opts.go(index)\n })\n },\n back: () => {\n tryNavigation(() => {\n opts.back()\n })\n },\n forward: () => {\n tryNavigation(() => {\n opts.forward()\n })\n },\n createHref: (str) => opts.createHref(str),\n block: (message) => {\n const payload: Blocker = {\n message,\n }\n\n blockers.push(payload)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== payload)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify: onUpdate,\n }\n}\n\nfunction assignKey(state: HistoryState) {\n if (!state) {\n state = {} as HistoryState\n }\n return {\n ...state,\n key: createRandomKey(),\n }\n}\n\n/**\n * Creates a history object that can be used to interact with the browser's\n * navigation. This is a lightweight API wrapping the browser's native methods.\n * It is designed to work with TanStack Router, but could be used as a standalone API as well.\n * IMPORTANT: This API implements history throttling via a microtask to prevent\n * excessive calls to the history API. In some browsers, calling history.pushState or\n * history.replaceState in quick succession can cause the browser to ignore subsequent\n * calls. This API smooths out those differences and ensures that your application\n * state will *eventually* match the browser state. In most cases, this is not a problem,\n * but if you need to ensure that the browser state is up to date, you can use the\n * `history.flush` method to immediately flush all pending state changes to the browser URL.\n * @param opts\n * @param opts.getHref A function that returns the current href (path + search + hash)\n * @param opts.createHref A function that takes a path and returns a href (path + search + hash)\n * @returns A history instance\n */\nexport function createBrowserHistory(opts?: {\n getHref?: () => string\n createHref?: (path: string) => string\n}): RouterHistory {\n const getHref =\n opts?.getHref ??\n (() =>\n `${window.location.pathname}${window.location.search}${window.location.hash}`)\n\n const createHref = opts?.createHref ?? ((path) => path)\n\n let currentLocation = parseLocation(getHref(), window.history.state)\n let rollbackLocation: HistoryLocation | undefined\n\n const getLocation = () => currentLocation\n\n let next:\n | undefined\n | {\n // This is the latest location that we were attempting to push/replace\n href: string\n // This is the latest state that we were attempting to push/replace\n state: any\n // This is the latest type that we were attempting to push/replace\n isPush: boolean\n }\n\n // Because we are proactively updating the location\n // in memory before actually updating the browser history,\n // we need to track when we are doing this so we don't\n // notify subscribers twice on the last update.\n let tracking = true\n\n // We need to track the current scheduled update to prevent\n // multiple updates from being scheduled at the same time.\n let scheduled: Promise<void> | undefined\n\n // This function is a wrapper to prevent any of the callback's\n // side effects from causing a subscriber notification\n const untrack = (fn: () => void) => {\n tracking = false\n fn()\n tracking = true\n }\n\n // This function flushes the next update to the browser history\n const flush = () => {\n // Do not notify subscribers about this push/replace call\n untrack(() => {\n if (!next) return\n window.history[next.isPush ? 'pushState' : 'replaceState'](\n next.state,\n '',\n next.href,\n )\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n rollbackLocation = undefined\n })\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n path: string,\n state: any,\n onUpdate: () => void,\n ) => {\n const href = createHref(path)\n\n if (!scheduled) {\n rollbackLocation = currentLocation\n }\n\n // Update the location in memory\n currentLocation = parseLocation(href, state)\n\n // Keep track of the next location we need to flush to the URL\n next = {\n href,\n state,\n isPush: next?.isPush || type === 'push',\n }\n\n // Notify subscribers\n onUpdate()\n\n if (!scheduled) {\n // Schedule an update to the browser history\n scheduled = Promise.resolve().then(() => flush())\n }\n }\n\n const onPushPop = () => {\n currentLocation = parseLocation(getHref(), window.history.state)\n history.notify()\n }\n\n var originalPushState = window.history.pushState\n var originalReplaceState = window.history.replaceState\n\n const history = createHistory({\n getLocation,\n pushState: (path, state, onUpdate) =>\n queueHistoryAction('push', path, state, onUpdate),\n replaceState: (path, state, onUpdate) =>\n queueHistoryAction('replace', path, state, onUpdate),\n back: () => window.history.back(),\n forward: () => window.history.forward(),\n go: (n) => window.history.go(n),\n createHref: (path) => createHref(path),\n flush,\n destroy: () => {\n window.history.pushState = originalPushState\n window.history.replaceState = originalReplaceState\n window.removeEventListener(pushStateEvent, onPushPop)\n window.removeEventListener(popStateEvent, onPushPop)\n },\n onBlocked: (onUpdate) => {\n // If a navigation is blocked, we need to rollback the location\n // that we optimistically updated in memory.\n if (rollbackLocation && currentLocation !== rollbackLocation) {\n currentLocation = rollbackLocation\n // Notify subscribers\n onUpdate()\n }\n },\n })\n\n window.addEventListener(pushStateEvent, onPushPop)\n window.addEventListener(popStateEvent, onPushPop)\n\n window.history.pushState = function () {\n let res = originalPushState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n window.history.replaceState = function () {\n let res = originalReplaceState.apply(window.history, arguments as any)\n if (tracking) history.notify()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(): RouterHistory {\n return createBrowserHistory({\n getHref: () => window.location.hash.substring(1),\n createHref: (path) => `#${path}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: string[]\n initialIndex?: number\n } = {\n initialEntries: ['/'],\n },\n): RouterHistory {\n const entries = opts.initialEntries\n let index = opts.initialIndex ?? entries.length - 1\n let currentState = {\n key: createRandomKey(),\n } as HistoryState\n\n const getLocation = () => parseLocation(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n pushState: (path, state) => {\n currentState = state\n entries.push(path)\n index++\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n index--\n },\n forward: () => {\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => window.history.go(n),\n createHref: (path) => path,\n })\n}\n\nfunction parseLocation(href: string, state: HistoryState): HistoryLocation {\n let hashIndex = href.indexOf('#')\n let searchIndex = href.indexOf('?')\n\n return {\n href,\n pathname: href.substring(\n 0,\n hashIndex > 0\n ? searchIndex > 0\n ? Math.min(hashIndex, searchIndex)\n : hashIndex\n : searchIndex > 0\n ? searchIndex\n : href.length,\n ),\n hash: hashIndex > -1 ? href.substring(hashIndex) : '',\n search:\n searchIndex > -1\n ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex)\n : '',\n state: state || {},\n }\n}\n\n// Thanks co-pilot!\nfunction createRandomKey() {\n return (Math.random() + 1).toString(36).substring(7)\n}\n"],"names":["pushStateEvent","popStateEvent","beforeUnloadEvent","beforeUnloadListener","event","preventDefault","returnValue","stopBlocking","removeEventListener","capture","createHistory","opts","location","getLocation","subscribers","Set","blockers","onUpdate","forEach","subscriber","tryNavigation","task","length","blocker","window","confirm","message","onBlocked","subscribe","cb","add","delete","push","path","state","assignKey","pushState","replace","replaceState","go","index","back","forward","createHref","str","block","payload","addEventListener","filter","b","flush","destroy","notify","key","createRandomKey","createBrowserHistory","getHref","pathname","search","hash","rollbackLocation","currentLocation","parseLocation","history","next","scheduled","tracking","isPush","href","undefined","fn","queueHistoryAction","type","Promise","resolve","then","onPushPop","originalPushState","originalReplaceState","n","res","apply","arguments","hashIndex","indexOf","searchIndex","substring","Math","min","slice","random","toString","initialEntries","entries","initialIndex","currentState"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/history",
3
3
  "author": "Tanner Linsley",
4
- "version": "0.0.1-beta.245",
4
+ "version": "0.0.1-beta.246",
5
5
  "license": "MIT",
6
6
  "repository": "tanstack/history",
7
7
  "homepage": "https://tanstack.com",
package/src/index.ts CHANGED
@@ -11,7 +11,7 @@ export interface RouterHistory {
11
11
  back: () => void
12
12
  forward: () => void
13
13
  createHref: (href: string) => string
14
- block: (blockerFn: BlockerFn) => () => void
14
+ block: (message: string) => () => void
15
15
  flush: () => void
16
16
  destroy: () => void
17
17
  notify: () => void
@@ -32,7 +32,9 @@ export interface HistoryState {
32
32
  key: string
33
33
  }
34
34
 
35
- type BlockerFn = (retry: () => void, cancel: () => void) => void
35
+ type Blocker = {
36
+ message: string
37
+ }
36
38
 
37
39
  const pushStateEvent = 'pushstate'
38
40
  const popStateEvent = 'popstate'
@@ -60,34 +62,28 @@ function createHistory(opts: {
60
62
  createHref: (path: string) => string
61
63
  flush?: () => void
62
64
  destroy?: () => void
65
+ onBlocked?: (onUpdate: () => void) => void
63
66
  }): RouterHistory {
64
67
  let location = opts.getLocation()
65
68
  let subscribers = new Set<() => void>()
66
- let blockers: BlockerFn[] = []
67
- let queue: (() => void)[] = []
69
+ let blockers: Blocker[] = []
68
70
 
69
71
  const onUpdate = () => {
70
72
  location = opts.getLocation()
71
73
  subscribers.forEach((subscriber) => subscriber())
72
74
  }
73
75
 
74
- const tryUnblock = () => {
76
+ const tryNavigation = (task: () => void) => {
75
77
  if (blockers.length) {
76
- blockers[0]?.(tryUnblock, () => {
77
- blockers = []
78
- stopBlocking()
79
- })
80
- return
81
- }
82
-
83
- while (queue.length) {
84
- queue.shift()?.()
78
+ for (let blocker of blockers) {
79
+ if (!window.confirm(blocker.message)) {
80
+ opts.onBlocked?.(onUpdate)
81
+ return
82
+ }
83
+ }
85
84
  }
86
- }
87
85
 
88
- const queueTask = (task: () => void) => {
89
- queue.push(task)
90
- tryUnblock()
86
+ task()
91
87
  }
92
88
 
93
89
  return {
@@ -103,34 +99,38 @@ function createHistory(opts: {
103
99
  },
104
100
  push: (path: string, state: any) => {
105
101
  state = assignKey(state)
106
- queueTask(() => {
102
+ tryNavigation(() => {
107
103
  opts.pushState(path, state, onUpdate)
108
104
  })
109
105
  },
110
106
  replace: (path: string, state: any) => {
111
107
  state = assignKey(state)
112
- queueTask(() => {
108
+ tryNavigation(() => {
113
109
  opts.replaceState(path, state, onUpdate)
114
110
  })
115
111
  },
116
112
  go: (index) => {
117
- queueTask(() => {
113
+ tryNavigation(() => {
118
114
  opts.go(index)
119
115
  })
120
116
  },
121
117
  back: () => {
122
- queueTask(() => {
118
+ tryNavigation(() => {
123
119
  opts.back()
124
120
  })
125
121
  },
126
122
  forward: () => {
127
- queueTask(() => {
123
+ tryNavigation(() => {
128
124
  opts.forward()
129
125
  })
130
126
  },
131
127
  createHref: (str) => opts.createHref(str),
132
- block: (cb) => {
133
- blockers.push(cb)
128
+ block: (message) => {
129
+ const payload: Blocker = {
130
+ message,
131
+ }
132
+
133
+ blockers.push(payload)
134
134
 
135
135
  if (blockers.length === 1) {
136
136
  addEventListener(beforeUnloadEvent, beforeUnloadListener, {
@@ -139,7 +139,7 @@ function createHistory(opts: {
139
139
  }
140
140
 
141
141
  return () => {
142
- blockers = blockers.filter((b) => b !== cb)
142
+ blockers = blockers.filter((b) => b !== payload)
143
143
 
144
144
  if (!blockers.length) {
145
145
  stopBlocking()
@@ -190,6 +190,7 @@ export function createBrowserHistory(opts?: {
190
190
  const createHref = opts?.createHref ?? ((path) => path)
191
191
 
192
192
  let currentLocation = parseLocation(getHref(), window.history.state)
193
+ let rollbackLocation: HistoryLocation | undefined
193
194
 
194
195
  const getLocation = () => currentLocation
195
196
 
@@ -235,6 +236,7 @@ export function createBrowserHistory(opts?: {
235
236
  // Reset the nextIsPush flag and clear the scheduled update
236
237
  next = undefined
237
238
  scheduled = undefined
239
+ rollbackLocation = undefined
238
240
  })
239
241
  }
240
242
 
@@ -247,6 +249,10 @@ export function createBrowserHistory(opts?: {
247
249
  ) => {
248
250
  const href = createHref(path)
249
251
 
252
+ if (!scheduled) {
253
+ rollbackLocation = currentLocation
254
+ }
255
+
250
256
  // Update the location in memory
251
257
  currentLocation = parseLocation(href, state)
252
258
 
@@ -256,6 +262,7 @@ export function createBrowserHistory(opts?: {
256
262
  state,
257
263
  isPush: next?.isPush || type === 'push',
258
264
  }
265
+
259
266
  // Notify subscribers
260
267
  onUpdate()
261
268
 
@@ -290,6 +297,15 @@ export function createBrowserHistory(opts?: {
290
297
  window.removeEventListener(pushStateEvent, onPushPop)
291
298
  window.removeEventListener(popStateEvent, onPushPop)
292
299
  },
300
+ onBlocked: (onUpdate) => {
301
+ // If a navigation is blocked, we need to rollback the location
302
+ // that we optimistically updated in memory.
303
+ if (rollbackLocation && currentLocation !== rollbackLocation) {
304
+ currentLocation = rollbackLocation
305
+ // Notify subscribers
306
+ onUpdate()
307
+ }
308
+ },
293
309
  })
294
310
 
295
311
  window.addEventListener(pushStateEvent, onPushPop)