@tanstack/history 1.58.15 → 1.61.0
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.
- package/dist/cjs/index.cjs +5 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +2 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +7 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -38,6 +38,9 @@ function createHistory(opts) {
|
|
|
38
38
|
get location() {
|
|
39
39
|
return location;
|
|
40
40
|
},
|
|
41
|
+
get length() {
|
|
42
|
+
return opts.getLength();
|
|
43
|
+
},
|
|
41
44
|
subscribers,
|
|
42
45
|
subscribe: (cb) => {
|
|
43
46
|
subscribers.add(cb);
|
|
@@ -162,6 +165,7 @@ function createBrowserHistory(opts) {
|
|
|
162
165
|
};
|
|
163
166
|
const history = createHistory({
|
|
164
167
|
getLocation,
|
|
168
|
+
getLength: () => win.history.length,
|
|
165
169
|
pushState: (href, state) => queueHistoryAction("push", href, state),
|
|
166
170
|
replaceState: (href, state) => queueHistoryAction("replace", href, state),
|
|
167
171
|
back: () => win.history.back(),
|
|
@@ -218,6 +222,7 @@ function createMemoryHistory(opts = {
|
|
|
218
222
|
const getLocation = () => parseHref(entries[index], currentState);
|
|
219
223
|
return createHistory({
|
|
220
224
|
getLocation,
|
|
225
|
+
getLength: () => entries.length,
|
|
221
226
|
pushState: (path, state) => {
|
|
222
227
|
currentState = state;
|
|
223
228
|
if (index < entries.length - 1) {
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","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 NavigateOptions {\n ignoreBlocker?: boolean\n}\nexport interface RouterHistory {\n location: HistoryLocation\n subscribers: Set<() => void>\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any, navigateOpts?: NavigateOptions) => void\n replace: (path: string, state?: any, navigateOpts?: NavigateOptions) => void\n go: (index: number, navigateOpts?: NavigateOptions) => void\n back: (navigateOpts?: NavigateOptions) => void\n forward: (navigateOpts?: NavigateOptions) => void\n createHref: (href: string) => string\n block: (blocker: BlockerFn) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n _ignoreSubscribers?: boolean\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 ShouldAllowNavigation = any\n\nexport type BlockerFn = () =>\n | Promise<ShouldAllowNavigation>\n | ShouldAllowNavigation\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-expect-error\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nexport function createHistory(opts: {\n getLocation: () => HistoryLocation\n pushState: (path: string, state: any) => void\n replaceState: (path: string, state: any) => 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 const subscribers = new Set<() => void>()\n let blockers: Array<BlockerFn> = []\n\n const notify = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryNavigation = async (\n task: () => void,\n navigateOpts?: NavigateOptions,\n ) => {\n const ignoreBlocker = navigateOpts?.ignoreBlocker ?? false\n if (!ignoreBlocker && typeof document !== 'undefined' && blockers.length) {\n for (const blocker of blockers) {\n const allowed = await blocker()\n if (!allowed) {\n opts.onBlocked?.(notify)\n return\n }\n }\n }\n\n task()\n }\n\n return {\n get location() {\n return location\n },\n subscribers,\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path, state, navigateOpts) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.pushState(path, state)\n notify()\n }, navigateOpts)\n },\n replace: (path, state, navigateOpts) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.replaceState(path, state)\n notify()\n }, navigateOpts)\n },\n go: (index, navigateOpts) => {\n tryNavigation(() => {\n opts.go(index)\n notify()\n }, navigateOpts)\n },\n back: (navigateOpts) => {\n tryNavigation(() => {\n opts.back()\n notify()\n }, navigateOpts)\n },\n forward: (navigateOpts) => {\n tryNavigation(() => {\n opts.forward()\n notify()\n }, navigateOpts)\n },\n createHref: (str) => opts.createHref(str),\n block: (blocker) => {\n blockers.push(blocker)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== blocker)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify,\n }\n}\n\nfunction assignKey(state: HistoryState | undefined) {\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 parseLocation?: () => HistoryLocation\n createHref?: (path: string) => string\n window?: any\n}): RouterHistory {\n const win =\n opts?.window ??\n (typeof document !== 'undefined' ? window : (undefined as any))\n\n const originalPushState = win.history.pushState\n const originalReplaceState = win.history.replaceState\n\n const createHref = opts?.createHref ?? ((path) => path)\n const parseLocation =\n opts?.parseLocation ??\n (() =>\n parseHref(\n `${win.location.pathname}${win.location.search}${win.location.hash}`,\n win.history.state,\n ))\n\n let currentLocation = parseLocation()\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 // 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 flushes the next update to the browser history\n const flush = () => {\n if (!next) {\n return\n }\n\n // We need to ignore any updates to the subscribers while we update the browser history\n history._ignoreSubscribers = true\n\n // Update the browser history\n ;(next.isPush ? win.history.pushState : win.history.replaceState)(\n next.state,\n '',\n next.href,\n )\n\n // Stop ignoring subscriber updates\n history._ignoreSubscribers = false\n\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n rollbackLocation = undefined\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n destHref: string,\n state: any,\n ) => {\n const href = createHref(destHref)\n\n if (!scheduled) {\n rollbackLocation = currentLocation\n }\n\n // Update the location in memory\n currentLocation = parseHref(destHref, 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 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()\n history.notify()\n }\n\n const history = createHistory({\n getLocation,\n pushState: (href, state) => queueHistoryAction('push', href, state),\n replaceState: (href, state) => queueHistoryAction('replace', href, state),\n back: () => win.history.back(),\n forward: () => win.history.forward(),\n go: (n) => win.history.go(n),\n createHref: (href) => createHref(href),\n flush,\n destroy: () => {\n win.history.pushState = originalPushState\n win.history.replaceState = originalReplaceState\n win.removeEventListener(pushStateEvent, onPushPop)\n win.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 win.addEventListener(pushStateEvent, onPushPop)\n win.addEventListener(popStateEvent, onPushPop)\n\n win.history.pushState = function (...args: Array<any>) {\n const res = originalPushState.apply(win.history, args)\n if (!history._ignoreSubscribers) onPushPop()\n return res\n }\n\n win.history.replaceState = function (...args: Array<any>) {\n const res = originalReplaceState.apply(win.history, args)\n if (!history._ignoreSubscribers) onPushPop()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(opts?: { window?: any }): RouterHistory {\n const win =\n opts?.window ??\n (typeof document !== 'undefined' ? window : (undefined as any))\n return createBrowserHistory({\n window: win,\n parseLocation: () => {\n const hashHref = win.location.hash.split('#').slice(1).join('#') ?? '/'\n return parseHref(hashHref, win.history.state)\n },\n createHref: (href) =>\n `${win.location.pathname}${win.location.search}#${href}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: Array<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 = () => parseHref(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n\n pushState: (path, state) => {\n currentState = state\n // Removes all subsequent entries after the current index to start a new branch\n if (index < entries.length - 1) {\n entries.splice(index + 1)\n }\n entries.push(path)\n index = Math.max(entries.length - 1, 0)\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n currentState = assignKey(currentState)\n index = Math.max(index - 1, 0)\n },\n forward: () => {\n currentState = assignKey(currentState)\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => {\n currentState = assignKey(currentState)\n index = Math.min(Math.max(index + n, 0), entries.length - 1)\n },\n createHref: (path) => path,\n })\n}\n\nexport function parseHref(\n href: string,\n state: HistoryState | undefined,\n): HistoryLocation {\n const hashIndex = href.indexOf('#')\n const 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":[],"mappings":";;AA6CA,MAAM,iBAAiB;AACvB,MAAM,gBAAgB;AACtB,MAAM,oBAAoB;AAE1B,MAAM,uBAAuB,CAAC,UAAiB;AAC7C,QAAM,eAAe;AAErB,SAAQ,MAAM,cAAc;AAC9B;AAEA,MAAM,eAAe,MAAM;AACzB,sBAAoB,mBAAmB,sBAAsB;AAAA,IAC3D,SAAS;AAAA,EAAA,CACV;AACH;AAEO,SAAS,cAAc,MAWZ;AACZ,MAAA,WAAW,KAAK;AACd,QAAA,kCAAkB;AACxB,MAAI,WAA6B,CAAA;AAEjC,QAAM,SAAS,MAAM;AACnB,eAAW,KAAK;AAChB,gBAAY,QAAQ,CAAC,eAAe,WAAY,CAAA;AAAA,EAAA;AAG5C,QAAA,gBAAgB,OACpB,MACA,iBACG;;AACG,UAAA,iBAAgB,6CAAc,kBAAiB;AACrD,QAAI,CAAC,iBAAiB,OAAO,aAAa,eAAe,SAAS,QAAQ;AACxE,iBAAW,WAAW,UAAU;AACxB,cAAA,UAAU,MAAM;AACtB,YAAI,CAAC,SAAS;AACZ,qBAAK,cAAL,8BAAiB;AACjB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEK;EAAA;AAGA,SAAA;AAAA,IACL,IAAI,WAAW;AACN,aAAA;AAAA,IACT;AAAA,IACA;AAAA,IACA,WAAW,CAAC,OAAmB;AAC7B,kBAAY,IAAI,EAAE;AAElB,aAAO,MAAM;AACX,oBAAY,OAAO,EAAE;AAAA,MAAA;AAAA,IAEzB;AAAA,IACA,MAAM,CAAC,MAAM,OAAO,iBAAiB;AACnC,cAAQ,UAAU,KAAK;AACvB,oBAAc,MAAM;AACb,aAAA,UAAU,MAAM,KAAK;AACnB;SACN,YAAY;AAAA,IACjB;AAAA,IACA,SAAS,CAAC,MAAM,OAAO,iBAAiB;AACtC,cAAQ,UAAU,KAAK;AACvB,oBAAc,MAAM;AACb,aAAA,aAAa,MAAM,KAAK;AACtB;SACN,YAAY;AAAA,IACjB;AAAA,IACA,IAAI,CAAC,OAAO,iBAAiB;AAC3B,oBAAc,MAAM;AAClB,aAAK,GAAG,KAAK;AACN;SACN,YAAY;AAAA,IACjB;AAAA,IACA,MAAM,CAAC,iBAAiB;AACtB,oBAAc,MAAM;AAClB,aAAK,KAAK;AACH;SACN,YAAY;AAAA,IACjB;AAAA,IACA,SAAS,CAAC,iBAAiB;AACzB,oBAAc,MAAM;AAClB,aAAK,QAAQ;AACN;SACN,YAAY;AAAA,IACjB;AAAA,IACA,YAAY,CAAC,QAAQ,KAAK,WAAW,GAAG;AAAA,IACxC,OAAO,CAAC,YAAY;AAClB,eAAS,KAAK,OAAO;AAEjB,UAAA,SAAS,WAAW,GAAG;AACzB,yBAAiB,mBAAmB,sBAAsB;AAAA,UACxD,SAAS;AAAA,QAAA,CACV;AAAA,MACH;AAEA,aAAO,MAAM;AACX,mBAAW,SAAS,OAAO,CAAC,MAAM,MAAM,OAAO;AAE3C,YAAA,CAAC,SAAS,QAAQ;AACP;QACf;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,OAAO,MAAA;;AAAM,wBAAK,UAAL;AAAA;AAAA,IACb,SAAS,MAAA;;AAAM,wBAAK,YAAL;AAAA;AAAA,IACf;AAAA,EAAA;AAEJ;AAEA,SAAS,UAAU,OAAiC;AAClD,MAAI,CAAC,OAAO;AACV,YAAQ,CAAA;AAAA,EACV;AACO,SAAA;AAAA,IACL,GAAG;AAAA,IACH,KAAK,gBAAgB;AAAA,EAAA;AAEzB;AAkBO,SAAS,qBAAqB,MAInB;AAChB,QAAM,OACJ,6BAAM,YACL,OAAO,aAAa,cAAc,SAAU;AAEzC,QAAA,oBAAoB,IAAI,QAAQ;AAChC,QAAA,uBAAuB,IAAI,QAAQ;AAEzC,QAAM,cAAa,6BAAM,gBAAe,CAAC,SAAS;AAC5C,QAAA,iBACJ,6BAAM,mBACL,MACC;AAAA,IACE,GAAG,IAAI,SAAS,QAAQ,GAAG,IAAI,SAAS,MAAM,GAAG,IAAI,SAAS,IAAI;AAAA,IAClE,IAAI,QAAQ;AAAA,EAAA;AAGlB,MAAI,kBAAkB;AAClB,MAAA;AAEJ,QAAM,cAAc,MAAM;AAEtB,MAAA;AAaA,MAAA;AAGJ,QAAM,QAAQ,MAAM;AAClB,QAAI,CAAC,MAAM;AACT;AAAA,IACF;AAGA,YAAQ,qBAAqB;AAG5B,KAAC,KAAK,SAAS,IAAI,QAAQ,YAAY,IAAI,QAAQ;AAAA,MAClD,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,IAAA;AAIP,YAAQ,qBAAqB;AAGtB,WAAA;AACK,gBAAA;AACO,uBAAA;AAAA,EAAA;AAIrB,QAAM,qBAAqB,CACzB,MACA,UACA,UACG;AACG,UAAA,OAAO,WAAW,QAAQ;AAEhC,QAAI,CAAC,WAAW;AACK,yBAAA;AAAA,IACrB;AAGkB,sBAAA,UAAU,UAAU,KAAK;AAGpC,WAAA;AAAA,MACL;AAAA,MACA;AAAA,MACA,SAAQ,6BAAM,WAAU,SAAS;AAAA,IAAA;AAGnC,QAAI,CAAC,WAAW;AAEd,kBAAY,QAAQ,QAAQ,EAAE,KAAK,MAAM,OAAO;AAAA,IAClD;AAAA,EAAA;AAGF,QAAM,YAAY,MAAM;AACtB,sBAAkB,cAAc;AAChC,YAAQ,OAAO;AAAA,EAAA;AAGjB,QAAM,UAAU,cAAc;AAAA,IAC5B;AAAA,IACA,WAAW,CAAC,MAAM,UAAU,mBAAmB,QAAQ,MAAM,KAAK;AAAA,IAClE,cAAc,CAAC,MAAM,UAAU,mBAAmB,WAAW,MAAM,KAAK;AAAA,IACxE,MAAM,MAAM,IAAI,QAAQ,KAAK;AAAA,IAC7B,SAAS,MAAM,IAAI,QAAQ,QAAQ;AAAA,IACnC,IAAI,CAAC,MAAM,IAAI,QAAQ,GAAG,CAAC;AAAA,IAC3B,YAAY,CAAC,SAAS,WAAW,IAAI;AAAA,IACrC;AAAA,IACA,SAAS,MAAM;AACb,UAAI,QAAQ,YAAY;AACxB,UAAI,QAAQ,eAAe;AACvB,UAAA,oBAAoB,gBAAgB,SAAS;AAC7C,UAAA,oBAAoB,eAAe,SAAS;AAAA,IAClD;AAAA,IACA,WAAW,CAAC,aAAa;AAGnB,UAAA,oBAAoB,oBAAoB,kBAAkB;AAC1C,0BAAA;AAET;MACX;AAAA,IACF;AAAA,EAAA,CACD;AAEG,MAAA,iBAAiB,gBAAgB,SAAS;AAC1C,MAAA,iBAAiB,eAAe,SAAS;AAEzC,MAAA,QAAQ,YAAY,YAAa,MAAkB;AACrD,UAAM,MAAM,kBAAkB,MAAM,IAAI,SAAS,IAAI;AACjD,QAAA,CAAC,QAAQ,mBAA8B;AACpC,WAAA;AAAA,EAAA;AAGL,MAAA,QAAQ,eAAe,YAAa,MAAkB;AACxD,UAAM,MAAM,qBAAqB,MAAM,IAAI,SAAS,IAAI;AACpD,QAAA,CAAC,QAAQ,mBAA8B;AACpC,WAAA;AAAA,EAAA;AAGF,SAAA;AACT;AAEO,SAAS,kBAAkB,MAAwC;AACxE,QAAM,OACJ,6BAAM,YACL,OAAO,aAAa,cAAc,SAAU;AAC/C,SAAO,qBAAqB;AAAA,IAC1B,QAAQ;AAAA,IACR,eAAe,MAAM;AACnB,YAAM,WAAW,IAAI,SAAS,KAAK,MAAM,GAAG,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK;AACpE,aAAO,UAAU,UAAU,IAAI,QAAQ,KAAK;AAAA,IAC9C;AAAA,IACA,YAAY,CAAC,SACX,GAAG,IAAI,SAAS,QAAQ,GAAG,IAAI,SAAS,MAAM,IAAI,IAAI;AAAA,EAAA,CACzD;AACH;AAEO,SAAS,oBACd,OAGI;AAAA,EACF,gBAAgB,CAAC,GAAG;AACtB,GACe;AACf,QAAM,UAAU,KAAK;AACrB,MAAI,QAAQ,KAAK,gBAAgB,QAAQ,SAAS;AAClD,MAAI,eAAe;AAAA,IACjB,KAAK,gBAAgB;AAAA,EAAA;AAGvB,QAAM,cAAc,MAAM,UAAU,QAAQ,KAAK,GAAI,YAAY;AAEjE,SAAO,cAAc;AAAA,IACnB;AAAA,IAEA,WAAW,CAAC,MAAM,UAAU;AACX,qBAAA;AAEX,UAAA,QAAQ,QAAQ,SAAS,GAAG;AACtB,gBAAA,OAAO,QAAQ,CAAC;AAAA,MAC1B;AACA,cAAQ,KAAK,IAAI;AACjB,cAAQ,KAAK,IAAI,QAAQ,SAAS,GAAG,CAAC;AAAA,IACxC;AAAA,IACA,cAAc,CAAC,MAAM,UAAU;AACd,qBAAA;AACf,cAAQ,KAAK,IAAI;AAAA,IACnB;AAAA,IACA,MAAM,MAAM;AACV,qBAAe,UAAU,YAAY;AACrC,cAAQ,KAAK,IAAI,QAAQ,GAAG,CAAC;AAAA,IAC/B;AAAA,IACA,SAAS,MAAM;AACb,qBAAe,UAAU,YAAY;AACrC,cAAQ,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,CAAC;AAAA,IAChD;AAAA,IACA,IAAI,CAAC,MAAM;AACT,qBAAe,UAAU,YAAY;AAC7B,cAAA,KAAK,IAAI,KAAK,IAAI,QAAQ,GAAG,CAAC,GAAG,QAAQ,SAAS,CAAC;AAAA,IAC7D;AAAA,IACA,YAAY,CAAC,SAAS;AAAA,EAAA,CACvB;AACH;AAEgB,SAAA,UACd,MACA,OACiB;AACX,QAAA,YAAY,KAAK,QAAQ,GAAG;AAC5B,QAAA,cAAc,KAAK,QAAQ,GAAG;AAE7B,SAAA;AAAA,IACL;AAAA,IACA,UAAU,KAAK;AAAA,MACb;AAAA,MACA,YAAY,IACR,cAAc,IACZ,KAAK,IAAI,WAAW,WAAW,IAC/B,YACF,cAAc,IACZ,cACA,KAAK;AAAA,IACb;AAAA,IACA,MAAM,YAAY,KAAK,KAAK,UAAU,SAAS,IAAI;AAAA,IACnD,QACE,cAAc,KACV,KAAK,MAAM,aAAa,cAAc,KAAK,SAAY,SAAS,IAChE;AAAA,IACN,OAAO,SAAS,CAAC;AAAA,EAAA;AAErB;AAGA,SAAS,kBAAkB;AACjB,UAAA,KAAK,WAAW,GAAG,SAAS,EAAE,EAAE,UAAU,CAAC;AACrD;;;;;;"}
|
|
1
|
+
{"version":3,"file":"index.cjs","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 NavigateOptions {\n ignoreBlocker?: boolean\n}\nexport interface RouterHistory {\n location: HistoryLocation\n length: number\n subscribers: Set<() => void>\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any, navigateOpts?: NavigateOptions) => void\n replace: (path: string, state?: any, navigateOpts?: NavigateOptions) => void\n go: (index: number, navigateOpts?: NavigateOptions) => void\n back: (navigateOpts?: NavigateOptions) => void\n forward: (navigateOpts?: NavigateOptions) => void\n createHref: (href: string) => string\n block: (blocker: BlockerFn) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n _ignoreSubscribers?: boolean\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 ShouldAllowNavigation = any\n\nexport type BlockerFn = () =>\n | Promise<ShouldAllowNavigation>\n | ShouldAllowNavigation\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-expect-error\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nexport function createHistory(opts: {\n getLocation: () => HistoryLocation\n getLength: () => number\n pushState: (path: string, state: any) => void\n replaceState: (path: string, state: any) => 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 const subscribers = new Set<() => void>()\n let blockers: Array<BlockerFn> = []\n\n const notify = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryNavigation = async (\n task: () => void,\n navigateOpts?: NavigateOptions,\n ) => {\n const ignoreBlocker = navigateOpts?.ignoreBlocker ?? false\n if (!ignoreBlocker && typeof document !== 'undefined' && blockers.length) {\n for (const blocker of blockers) {\n const allowed = await blocker()\n if (!allowed) {\n opts.onBlocked?.(notify)\n return\n }\n }\n }\n\n task()\n }\n\n return {\n get location() {\n return location\n },\n get length() {\n return opts.getLength()\n },\n subscribers,\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path, state, navigateOpts) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.pushState(path, state)\n notify()\n }, navigateOpts)\n },\n replace: (path, state, navigateOpts) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.replaceState(path, state)\n notify()\n }, navigateOpts)\n },\n go: (index, navigateOpts) => {\n tryNavigation(() => {\n opts.go(index)\n notify()\n }, navigateOpts)\n },\n back: (navigateOpts) => {\n tryNavigation(() => {\n opts.back()\n notify()\n }, navigateOpts)\n },\n forward: (navigateOpts) => {\n tryNavigation(() => {\n opts.forward()\n notify()\n }, navigateOpts)\n },\n createHref: (str) => opts.createHref(str),\n block: (blocker) => {\n blockers.push(blocker)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== blocker)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify,\n }\n}\n\nfunction assignKey(state: HistoryState | undefined) {\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 parseLocation?: () => HistoryLocation\n createHref?: (path: string) => string\n window?: any\n}): RouterHistory {\n const win =\n opts?.window ??\n (typeof document !== 'undefined' ? window : (undefined as any))\n\n const originalPushState = win.history.pushState\n const originalReplaceState = win.history.replaceState\n\n const createHref = opts?.createHref ?? ((path) => path)\n const parseLocation =\n opts?.parseLocation ??\n (() =>\n parseHref(\n `${win.location.pathname}${win.location.search}${win.location.hash}`,\n win.history.state,\n ))\n\n let currentLocation = parseLocation()\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 // 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 flushes the next update to the browser history\n const flush = () => {\n if (!next) {\n return\n }\n\n // We need to ignore any updates to the subscribers while we update the browser history\n history._ignoreSubscribers = true\n\n // Update the browser history\n ;(next.isPush ? win.history.pushState : win.history.replaceState)(\n next.state,\n '',\n next.href,\n )\n\n // Stop ignoring subscriber updates\n history._ignoreSubscribers = false\n\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n rollbackLocation = undefined\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n destHref: string,\n state: any,\n ) => {\n const href = createHref(destHref)\n\n if (!scheduled) {\n rollbackLocation = currentLocation\n }\n\n // Update the location in memory\n currentLocation = parseHref(destHref, 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 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()\n history.notify()\n }\n\n const history = createHistory({\n getLocation,\n getLength: () => win.history.length,\n pushState: (href, state) => queueHistoryAction('push', href, state),\n replaceState: (href, state) => queueHistoryAction('replace', href, state),\n back: () => win.history.back(),\n forward: () => win.history.forward(),\n go: (n) => win.history.go(n),\n createHref: (href) => createHref(href),\n flush,\n destroy: () => {\n win.history.pushState = originalPushState\n win.history.replaceState = originalReplaceState\n win.removeEventListener(pushStateEvent, onPushPop)\n win.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 win.addEventListener(pushStateEvent, onPushPop)\n win.addEventListener(popStateEvent, onPushPop)\n\n win.history.pushState = function (...args: Array<any>) {\n const res = originalPushState.apply(win.history, args)\n if (!history._ignoreSubscribers) onPushPop()\n return res\n }\n\n win.history.replaceState = function (...args: Array<any>) {\n const res = originalReplaceState.apply(win.history, args)\n if (!history._ignoreSubscribers) onPushPop()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(opts?: { window?: any }): RouterHistory {\n const win =\n opts?.window ??\n (typeof document !== 'undefined' ? window : (undefined as any))\n return createBrowserHistory({\n window: win,\n parseLocation: () => {\n const hashHref = win.location.hash.split('#').slice(1).join('#') ?? '/'\n return parseHref(hashHref, win.history.state)\n },\n createHref: (href) =>\n `${win.location.pathname}${win.location.search}#${href}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: Array<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 = () => parseHref(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n getLength: () => entries.length,\n pushState: (path, state) => {\n currentState = state\n // Removes all subsequent entries after the current index to start a new branch\n if (index < entries.length - 1) {\n entries.splice(index + 1)\n }\n entries.push(path)\n index = Math.max(entries.length - 1, 0)\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n currentState = assignKey(currentState)\n index = Math.max(index - 1, 0)\n },\n forward: () => {\n currentState = assignKey(currentState)\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => {\n currentState = assignKey(currentState)\n index = Math.min(Math.max(index + n, 0), entries.length - 1)\n },\n createHref: (path) => path,\n })\n}\n\nexport function parseHref(\n href: string,\n state: HistoryState | undefined,\n): HistoryLocation {\n const hashIndex = href.indexOf('#')\n const 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":[],"mappings":"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"}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -3,6 +3,7 @@ export interface NavigateOptions {
|
|
|
3
3
|
}
|
|
4
4
|
export interface RouterHistory {
|
|
5
5
|
location: HistoryLocation;
|
|
6
|
+
length: number;
|
|
6
7
|
subscribers: Set<() => void>;
|
|
7
8
|
subscribe: (cb: () => void) => () => void;
|
|
8
9
|
push: (path: string, state?: any, navigateOpts?: NavigateOptions) => void;
|
|
@@ -33,6 +34,7 @@ type ShouldAllowNavigation = any;
|
|
|
33
34
|
export type BlockerFn = () => Promise<ShouldAllowNavigation> | ShouldAllowNavigation;
|
|
34
35
|
export declare function createHistory(opts: {
|
|
35
36
|
getLocation: () => HistoryLocation;
|
|
37
|
+
getLength: () => number;
|
|
36
38
|
pushState: (path: string, state: any) => void;
|
|
37
39
|
replaceState: (path: string, state: any) => void;
|
|
38
40
|
go: (n: number) => void;
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export interface NavigateOptions {
|
|
|
3
3
|
}
|
|
4
4
|
export interface RouterHistory {
|
|
5
5
|
location: HistoryLocation;
|
|
6
|
+
length: number;
|
|
6
7
|
subscribers: Set<() => void>;
|
|
7
8
|
subscribe: (cb: () => void) => () => void;
|
|
8
9
|
push: (path: string, state?: any, navigateOpts?: NavigateOptions) => void;
|
|
@@ -33,6 +34,7 @@ type ShouldAllowNavigation = any;
|
|
|
33
34
|
export type BlockerFn = () => Promise<ShouldAllowNavigation> | ShouldAllowNavigation;
|
|
34
35
|
export declare function createHistory(opts: {
|
|
35
36
|
getLocation: () => HistoryLocation;
|
|
37
|
+
getLength: () => number;
|
|
36
38
|
pushState: (path: string, state: any) => void;
|
|
37
39
|
replaceState: (path: string, state: any) => void;
|
|
38
40
|
go: (n: number) => void;
|
package/dist/esm/index.js
CHANGED
|
@@ -36,6 +36,9 @@ function createHistory(opts) {
|
|
|
36
36
|
get location() {
|
|
37
37
|
return location;
|
|
38
38
|
},
|
|
39
|
+
get length() {
|
|
40
|
+
return opts.getLength();
|
|
41
|
+
},
|
|
39
42
|
subscribers,
|
|
40
43
|
subscribe: (cb) => {
|
|
41
44
|
subscribers.add(cb);
|
|
@@ -160,6 +163,7 @@ function createBrowserHistory(opts) {
|
|
|
160
163
|
};
|
|
161
164
|
const history = createHistory({
|
|
162
165
|
getLocation,
|
|
166
|
+
getLength: () => win.history.length,
|
|
163
167
|
pushState: (href, state) => queueHistoryAction("push", href, state),
|
|
164
168
|
replaceState: (href, state) => queueHistoryAction("replace", href, state),
|
|
165
169
|
back: () => win.history.back(),
|
|
@@ -216,6 +220,7 @@ function createMemoryHistory(opts = {
|
|
|
216
220
|
const getLocation = () => parseHref(entries[index], currentState);
|
|
217
221
|
return createHistory({
|
|
218
222
|
getLocation,
|
|
223
|
+
getLength: () => entries.length,
|
|
219
224
|
pushState: (path, state) => {
|
|
220
225
|
currentState = state;
|
|
221
226
|
if (index < entries.length - 1) {
|
package/dist/esm/index.js.map
CHANGED
|
@@ -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 NavigateOptions {\n ignoreBlocker?: boolean\n}\nexport interface RouterHistory {\n location: HistoryLocation\n subscribers: Set<() => void>\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any, navigateOpts?: NavigateOptions) => void\n replace: (path: string, state?: any, navigateOpts?: NavigateOptions) => void\n go: (index: number, navigateOpts?: NavigateOptions) => void\n back: (navigateOpts?: NavigateOptions) => void\n forward: (navigateOpts?: NavigateOptions) => void\n createHref: (href: string) => string\n block: (blocker: BlockerFn) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n _ignoreSubscribers?: boolean\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 ShouldAllowNavigation = any\n\nexport type BlockerFn = () =>\n | Promise<ShouldAllowNavigation>\n | ShouldAllowNavigation\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-expect-error\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nexport function createHistory(opts: {\n getLocation: () => HistoryLocation\n pushState: (path: string, state: any) => void\n replaceState: (path: string, state: any) => 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 const subscribers = new Set<() => void>()\n let blockers: Array<BlockerFn> = []\n\n const notify = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryNavigation = async (\n task: () => void,\n navigateOpts?: NavigateOptions,\n ) => {\n const ignoreBlocker = navigateOpts?.ignoreBlocker ?? false\n if (!ignoreBlocker && typeof document !== 'undefined' && blockers.length) {\n for (const blocker of blockers) {\n const allowed = await blocker()\n if (!allowed) {\n opts.onBlocked?.(notify)\n return\n }\n }\n }\n\n task()\n }\n\n return {\n get location() {\n return location\n },\n subscribers,\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path, state, navigateOpts) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.pushState(path, state)\n notify()\n }, navigateOpts)\n },\n replace: (path, state, navigateOpts) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.replaceState(path, state)\n notify()\n }, navigateOpts)\n },\n go: (index, navigateOpts) => {\n tryNavigation(() => {\n opts.go(index)\n notify()\n }, navigateOpts)\n },\n back: (navigateOpts) => {\n tryNavigation(() => {\n opts.back()\n notify()\n }, navigateOpts)\n },\n forward: (navigateOpts) => {\n tryNavigation(() => {\n opts.forward()\n notify()\n }, navigateOpts)\n },\n createHref: (str) => opts.createHref(str),\n block: (blocker) => {\n blockers.push(blocker)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== blocker)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify,\n }\n}\n\nfunction assignKey(state: HistoryState | undefined) {\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 parseLocation?: () => HistoryLocation\n createHref?: (path: string) => string\n window?: any\n}): RouterHistory {\n const win =\n opts?.window ??\n (typeof document !== 'undefined' ? window : (undefined as any))\n\n const originalPushState = win.history.pushState\n const originalReplaceState = win.history.replaceState\n\n const createHref = opts?.createHref ?? ((path) => path)\n const parseLocation =\n opts?.parseLocation ??\n (() =>\n parseHref(\n `${win.location.pathname}${win.location.search}${win.location.hash}`,\n win.history.state,\n ))\n\n let currentLocation = parseLocation()\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 // 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 flushes the next update to the browser history\n const flush = () => {\n if (!next) {\n return\n }\n\n // We need to ignore any updates to the subscribers while we update the browser history\n history._ignoreSubscribers = true\n\n // Update the browser history\n ;(next.isPush ? win.history.pushState : win.history.replaceState)(\n next.state,\n '',\n next.href,\n )\n\n // Stop ignoring subscriber updates\n history._ignoreSubscribers = false\n\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n rollbackLocation = undefined\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n destHref: string,\n state: any,\n ) => {\n const href = createHref(destHref)\n\n if (!scheduled) {\n rollbackLocation = currentLocation\n }\n\n // Update the location in memory\n currentLocation = parseHref(destHref, 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 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()\n history.notify()\n }\n\n const history = createHistory({\n getLocation,\n pushState: (href, state) => queueHistoryAction('push', href, state),\n replaceState: (href, state) => queueHistoryAction('replace', href, state),\n back: () => win.history.back(),\n forward: () => win.history.forward(),\n go: (n) => win.history.go(n),\n createHref: (href) => createHref(href),\n flush,\n destroy: () => {\n win.history.pushState = originalPushState\n win.history.replaceState = originalReplaceState\n win.removeEventListener(pushStateEvent, onPushPop)\n win.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 win.addEventListener(pushStateEvent, onPushPop)\n win.addEventListener(popStateEvent, onPushPop)\n\n win.history.pushState = function (...args: Array<any>) {\n const res = originalPushState.apply(win.history, args)\n if (!history._ignoreSubscribers) onPushPop()\n return res\n }\n\n win.history.replaceState = function (...args: Array<any>) {\n const res = originalReplaceState.apply(win.history, args)\n if (!history._ignoreSubscribers) onPushPop()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(opts?: { window?: any }): RouterHistory {\n const win =\n opts?.window ??\n (typeof document !== 'undefined' ? window : (undefined as any))\n return createBrowserHistory({\n window: win,\n parseLocation: () => {\n const hashHref = win.location.hash.split('#').slice(1).join('#') ?? '/'\n return parseHref(hashHref, win.history.state)\n },\n createHref: (href) =>\n `${win.location.pathname}${win.location.search}#${href}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: Array<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 = () => parseHref(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n\n pushState: (path, state) => {\n currentState = state\n // Removes all subsequent entries after the current index to start a new branch\n if (index < entries.length - 1) {\n entries.splice(index + 1)\n }\n entries.push(path)\n index = Math.max(entries.length - 1, 0)\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n currentState = assignKey(currentState)\n index = Math.max(index - 1, 0)\n },\n forward: () => {\n currentState = assignKey(currentState)\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => {\n currentState = assignKey(currentState)\n index = Math.min(Math.max(index + n, 0), entries.length - 1)\n },\n createHref: (path) => path,\n })\n}\n\nexport function parseHref(\n href: string,\n state: HistoryState | undefined,\n): HistoryLocation {\n const hashIndex = href.indexOf('#')\n const 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":[],"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 NavigateOptions {\n ignoreBlocker?: boolean\n}\nexport interface RouterHistory {\n location: HistoryLocation\n length: number\n subscribers: Set<() => void>\n subscribe: (cb: () => void) => () => void\n push: (path: string, state?: any, navigateOpts?: NavigateOptions) => void\n replace: (path: string, state?: any, navigateOpts?: NavigateOptions) => void\n go: (index: number, navigateOpts?: NavigateOptions) => void\n back: (navigateOpts?: NavigateOptions) => void\n forward: (navigateOpts?: NavigateOptions) => void\n createHref: (href: string) => string\n block: (blocker: BlockerFn) => () => void\n flush: () => void\n destroy: () => void\n notify: () => void\n _ignoreSubscribers?: boolean\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 ShouldAllowNavigation = any\n\nexport type BlockerFn = () =>\n | Promise<ShouldAllowNavigation>\n | ShouldAllowNavigation\n\nconst pushStateEvent = 'pushstate'\nconst popStateEvent = 'popstate'\nconst beforeUnloadEvent = 'beforeunload'\n\nconst beforeUnloadListener = (event: Event) => {\n event.preventDefault()\n // @ts-expect-error\n return (event.returnValue = '')\n}\n\nconst stopBlocking = () => {\n removeEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n}\n\nexport function createHistory(opts: {\n getLocation: () => HistoryLocation\n getLength: () => number\n pushState: (path: string, state: any) => void\n replaceState: (path: string, state: any) => 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 const subscribers = new Set<() => void>()\n let blockers: Array<BlockerFn> = []\n\n const notify = () => {\n location = opts.getLocation()\n subscribers.forEach((subscriber) => subscriber())\n }\n\n const tryNavigation = async (\n task: () => void,\n navigateOpts?: NavigateOptions,\n ) => {\n const ignoreBlocker = navigateOpts?.ignoreBlocker ?? false\n if (!ignoreBlocker && typeof document !== 'undefined' && blockers.length) {\n for (const blocker of blockers) {\n const allowed = await blocker()\n if (!allowed) {\n opts.onBlocked?.(notify)\n return\n }\n }\n }\n\n task()\n }\n\n return {\n get location() {\n return location\n },\n get length() {\n return opts.getLength()\n },\n subscribers,\n subscribe: (cb: () => void) => {\n subscribers.add(cb)\n\n return () => {\n subscribers.delete(cb)\n }\n },\n push: (path, state, navigateOpts) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.pushState(path, state)\n notify()\n }, navigateOpts)\n },\n replace: (path, state, navigateOpts) => {\n state = assignKey(state)\n tryNavigation(() => {\n opts.replaceState(path, state)\n notify()\n }, navigateOpts)\n },\n go: (index, navigateOpts) => {\n tryNavigation(() => {\n opts.go(index)\n notify()\n }, navigateOpts)\n },\n back: (navigateOpts) => {\n tryNavigation(() => {\n opts.back()\n notify()\n }, navigateOpts)\n },\n forward: (navigateOpts) => {\n tryNavigation(() => {\n opts.forward()\n notify()\n }, navigateOpts)\n },\n createHref: (str) => opts.createHref(str),\n block: (blocker) => {\n blockers.push(blocker)\n\n if (blockers.length === 1) {\n addEventListener(beforeUnloadEvent, beforeUnloadListener, {\n capture: true,\n })\n }\n\n return () => {\n blockers = blockers.filter((b) => b !== blocker)\n\n if (!blockers.length) {\n stopBlocking()\n }\n }\n },\n flush: () => opts.flush?.(),\n destroy: () => opts.destroy?.(),\n notify,\n }\n}\n\nfunction assignKey(state: HistoryState | undefined) {\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 parseLocation?: () => HistoryLocation\n createHref?: (path: string) => string\n window?: any\n}): RouterHistory {\n const win =\n opts?.window ??\n (typeof document !== 'undefined' ? window : (undefined as any))\n\n const originalPushState = win.history.pushState\n const originalReplaceState = win.history.replaceState\n\n const createHref = opts?.createHref ?? ((path) => path)\n const parseLocation =\n opts?.parseLocation ??\n (() =>\n parseHref(\n `${win.location.pathname}${win.location.search}${win.location.hash}`,\n win.history.state,\n ))\n\n let currentLocation = parseLocation()\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 // 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 flushes the next update to the browser history\n const flush = () => {\n if (!next) {\n return\n }\n\n // We need to ignore any updates to the subscribers while we update the browser history\n history._ignoreSubscribers = true\n\n // Update the browser history\n ;(next.isPush ? win.history.pushState : win.history.replaceState)(\n next.state,\n '',\n next.href,\n )\n\n // Stop ignoring subscriber updates\n history._ignoreSubscribers = false\n\n // Reset the nextIsPush flag and clear the scheduled update\n next = undefined\n scheduled = undefined\n rollbackLocation = undefined\n }\n\n // This function queues up a call to update the browser history\n const queueHistoryAction = (\n type: 'push' | 'replace',\n destHref: string,\n state: any,\n ) => {\n const href = createHref(destHref)\n\n if (!scheduled) {\n rollbackLocation = currentLocation\n }\n\n // Update the location in memory\n currentLocation = parseHref(destHref, 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 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()\n history.notify()\n }\n\n const history = createHistory({\n getLocation,\n getLength: () => win.history.length,\n pushState: (href, state) => queueHistoryAction('push', href, state),\n replaceState: (href, state) => queueHistoryAction('replace', href, state),\n back: () => win.history.back(),\n forward: () => win.history.forward(),\n go: (n) => win.history.go(n),\n createHref: (href) => createHref(href),\n flush,\n destroy: () => {\n win.history.pushState = originalPushState\n win.history.replaceState = originalReplaceState\n win.removeEventListener(pushStateEvent, onPushPop)\n win.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 win.addEventListener(pushStateEvent, onPushPop)\n win.addEventListener(popStateEvent, onPushPop)\n\n win.history.pushState = function (...args: Array<any>) {\n const res = originalPushState.apply(win.history, args)\n if (!history._ignoreSubscribers) onPushPop()\n return res\n }\n\n win.history.replaceState = function (...args: Array<any>) {\n const res = originalReplaceState.apply(win.history, args)\n if (!history._ignoreSubscribers) onPushPop()\n return res\n }\n\n return history\n}\n\nexport function createHashHistory(opts?: { window?: any }): RouterHistory {\n const win =\n opts?.window ??\n (typeof document !== 'undefined' ? window : (undefined as any))\n return createBrowserHistory({\n window: win,\n parseLocation: () => {\n const hashHref = win.location.hash.split('#').slice(1).join('#') ?? '/'\n return parseHref(hashHref, win.history.state)\n },\n createHref: (href) =>\n `${win.location.pathname}${win.location.search}#${href}`,\n })\n}\n\nexport function createMemoryHistory(\n opts: {\n initialEntries: Array<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 = () => parseHref(entries[index]!, currentState)\n\n return createHistory({\n getLocation,\n getLength: () => entries.length,\n pushState: (path, state) => {\n currentState = state\n // Removes all subsequent entries after the current index to start a new branch\n if (index < entries.length - 1) {\n entries.splice(index + 1)\n }\n entries.push(path)\n index = Math.max(entries.length - 1, 0)\n },\n replaceState: (path, state) => {\n currentState = state\n entries[index] = path\n },\n back: () => {\n currentState = assignKey(currentState)\n index = Math.max(index - 1, 0)\n },\n forward: () => {\n currentState = assignKey(currentState)\n index = Math.min(index + 1, entries.length - 1)\n },\n go: (n) => {\n currentState = assignKey(currentState)\n index = Math.min(Math.max(index + n, 0), entries.length - 1)\n },\n createHref: (path) => path,\n })\n}\n\nexport function parseHref(\n href: string,\n state: HistoryState | undefined,\n): HistoryLocation {\n const hashIndex = href.indexOf('#')\n const 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":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export interface NavigateOptions {
|
|
|
7
7
|
}
|
|
8
8
|
export interface RouterHistory {
|
|
9
9
|
location: HistoryLocation
|
|
10
|
+
length: number
|
|
10
11
|
subscribers: Set<() => void>
|
|
11
12
|
subscribe: (cb: () => void) => () => void
|
|
12
13
|
push: (path: string, state?: any, navigateOpts?: NavigateOptions) => void
|
|
@@ -61,6 +62,7 @@ const stopBlocking = () => {
|
|
|
61
62
|
|
|
62
63
|
export function createHistory(opts: {
|
|
63
64
|
getLocation: () => HistoryLocation
|
|
65
|
+
getLength: () => number
|
|
64
66
|
pushState: (path: string, state: any) => void
|
|
65
67
|
replaceState: (path: string, state: any) => void
|
|
66
68
|
go: (n: number) => void
|
|
@@ -102,6 +104,9 @@ export function createHistory(opts: {
|
|
|
102
104
|
get location() {
|
|
103
105
|
return location
|
|
104
106
|
},
|
|
107
|
+
get length() {
|
|
108
|
+
return opts.getLength()
|
|
109
|
+
},
|
|
105
110
|
subscribers,
|
|
106
111
|
subscribe: (cb: () => void) => {
|
|
107
112
|
subscribers.add(cb)
|
|
@@ -293,6 +298,7 @@ export function createBrowserHistory(opts?: {
|
|
|
293
298
|
|
|
294
299
|
const history = createHistory({
|
|
295
300
|
getLocation,
|
|
301
|
+
getLength: () => win.history.length,
|
|
296
302
|
pushState: (href, state) => queueHistoryAction('push', href, state),
|
|
297
303
|
replaceState: (href, state) => queueHistoryAction('replace', href, state),
|
|
298
304
|
back: () => win.history.back(),
|
|
@@ -368,7 +374,7 @@ export function createMemoryHistory(
|
|
|
368
374
|
|
|
369
375
|
return createHistory({
|
|
370
376
|
getLocation,
|
|
371
|
-
|
|
377
|
+
getLength: () => entries.length,
|
|
372
378
|
pushState: (path, state) => {
|
|
373
379
|
currentState = state
|
|
374
380
|
// Removes all subsequent entries after the current index to start a new branch
|