navgo 3.0.8 → 4.0.2

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.
Files changed (4) hide show
  1. package/index.d.ts +21 -21
  2. package/index.js +15 -13
  3. package/package.json +1 -1
  4. package/readme.md +12 -12
package/index.d.ts CHANGED
@@ -7,23 +7,23 @@ export type Params = Record<string, string | null | undefined>
7
7
 
8
8
  /** Built-in validator helpers shape. */
9
9
  export interface ValidatorHelpers {
10
- int(_opts?: {
10
+ int(opts?: {
11
11
  min?: number | null
12
12
  max?: number | null
13
- }): (_value: string | null | undefined) => boolean
14
- one_of(_values: Iterable<string>): (_value: string | null | undefined) => boolean
13
+ }): (value: string | null | undefined) => boolean
14
+ one_of(values: Iterable<string>): (value: string | null | undefined) => boolean
15
15
  }
16
16
 
17
17
  /** Optional per-route hooks recognized by Navgo. */
18
18
  export interface Hooks {
19
19
  /** Validate params with custom per-param validators. Return `false` to skip a match. */
20
- param_validators?: Record<string, (_value: string | null | undefined) => boolean>
20
+ param_validators?: Record<string, (value: string | null | undefined) => boolean>
21
21
  /** Load data for a route before navigation. May return a Promise or an array of values/promises. */
22
- loaders?(_params: Params): unknown | Promise<unknown> | Array<unknown | Promise<unknown>>
22
+ loader?(params: Params): unknown | Promise<unknown> | Array<unknown | Promise<unknown>>
23
23
  /** Predicate used during match(); may be async. If it returns `false`, the route is skipped. */
24
- validate?(_params: Params): boolean | Promise<boolean>
24
+ validate?(params: Params): boolean | Promise<boolean>
25
25
  /** Route-level navigation guard, called on the current route when leaving it. Synchronous only; call `nav.cancel()` to prevent navigation. */
26
- before_route_leave?(_nav: Navigation): void
26
+ before_route_leave?(nav: Navigation): void
27
27
  }
28
28
 
29
29
  export interface NavigationTarget {
@@ -31,7 +31,7 @@ export interface NavigationTarget {
31
31
  params: Params
32
32
  /** The matched route tuple from your original `routes` list; `null` when unmatched (e.g. external). */
33
33
  route: RouteTuple | null
34
- /** Optional data from route loaders when available. */
34
+ /** Optional data from route loader when available. */
35
35
  data?: unknown
36
36
  }
37
37
 
@@ -77,10 +77,10 @@ export interface Options {
77
77
  preload_on_hover?: boolean
78
78
  /** Attach instance to window as `window.navgo`. Default true. */
79
79
  attach_to_window?: boolean
80
- /** Global hook fired after per-route `before_route_leave`, before loaders/history change. Can cancel. */
81
- before_navigate?(_nav: Navigation): void
80
+ /** Global hook fired after per-route `before_route_leave`, before loader/history change. Can cancel. */
81
+ before_navigate?(nav: Navigation): void
82
82
  /** Global hook fired after routing completes (data loaded, URL updated, handlers run). */
83
- after_navigate?(_nav: Navigation): void
83
+ after_navigate?(nav: Navigation): void
84
84
  /** Optional hook awaited after `after_navigate` and before scroll handling.
85
85
  * Useful for UI frameworks (e.g., Svelte) to flush DOM updates so anchor/top
86
86
  * scrolling lands on the correct elements.
@@ -90,24 +90,24 @@ export interface Options {
90
90
  * Triggers for shallow pushes/replaces, hash changes, popstate-shallow, 404s, and full navigations.
91
91
  * Receives the router's current snapshot (eg `{ url: URL, route: RouteTuple|null, params: Params }`).
92
92
  */
93
- url_changed?(_payload: any): void
93
+ url_changed?(payload: any): void
94
94
  }
95
95
 
96
96
  /** Navgo default export: class-based router. */
97
97
  export default class Navgo<T = unknown> {
98
- constructor(_routes?: Array<RouteTuple<T>>, _opts?: Options)
98
+ constructor(routes?: Array<RouteTuple<T>>, opts?: Options)
99
99
  /** Format `url` relative to the configured base. */
100
- format(_url: string): string | false
101
- /** SvelteKit-like navigation that runs loaders before updating the URL. */
102
- goto(_url: string, _opts?: { replace?: boolean }): Promise<void>
100
+ format(url: string): string | false
101
+ /** SvelteKit-like navigation that runs `loader` before updating the URL. */
102
+ goto(url: string, opts?: { replace?: boolean }): Promise<void>
103
103
  /** Shallow push — updates URL/state without triggering handlers. */
104
- push_state(_url?: string | URL, _state?: any): void
104
+ push_state(url?: string | URL, state?: any): void
105
105
  /** Shallow replace — updates URL/state without triggering handlers. */
106
- replace_state(_url?: string | URL, _state?: any): void
107
- /** Manually preload loaders for a URL (deduped). */
108
- preload(_url: string): Promise<unknown | void>
106
+ replace_state(url?: string | URL, state?: any): void
107
+ /** Manually preload `loader` for a URL (deduped). */
108
+ preload(url: string): Promise<unknown | void>
109
109
  /** Try to match `url`; returns route tuple and params or `null`. Supports async `validate`. */
110
- match(_url: string): Promise<MatchResult<T> | null>
110
+ match(url: string): Promise<MatchResult<T> | null>
111
111
  /** Attach history + click listeners and immediately process current location. */
112
112
  init(): Promise<void>
113
113
  /** Remove listeners installed by `init()`. */
package/index.js CHANGED
@@ -97,12 +97,12 @@ export default class Navgo {
97
97
 
98
98
  const st = ev?.state?.__navgo
99
99
  ℹ('[🧭 event:popstate]', st)
100
- // Hash-only or state-only change: pathname+search unchanged -> skip loaders
100
+ // Hash-only or state-only change: pathname+search unchanged -> skip loader
101
101
  const cur = this.#current.url
102
102
  const target = new URL(location.href)
103
103
  if (cur && target.pathname === cur.pathname) {
104
104
  this.#current.url = target
105
- ℹ(' - [🧭 event:popstate]', 'same path+search; skip loaders')
105
+ ℹ(' - [🧭 event:popstate]', 'same path+search; skip loader')
106
106
  this.#apply_scroll(ev)
107
107
  this.route.set(this.#current)
108
108
  return
@@ -110,7 +110,7 @@ export default class Navgo {
110
110
  // Explicit shallow entries (pushState/replaceState) regardless of path
111
111
  if (st?.shallow) {
112
112
  this.#current.url = target
113
- ℹ(' - [🧭 event:popstate]', 'shallow entry; skip loaders')
113
+ ℹ(' - [🧭 event:popstate]', 'shallow entry; skip loader')
114
114
  this.#apply_scroll(ev)
115
115
  this.route.set(this.#current)
116
116
  return
@@ -254,8 +254,8 @@ export default class Navgo {
254
254
  return true
255
255
  }
256
256
 
257
- async #run_loaders(route, params) {
258
- const ret_val = route[1].loaders?.(params)
257
+ async #run_loader(route, params) {
258
+ const ret_val = route[1].loader?.(params)
259
259
  return Array.isArray(ret_val) ? Promise.all(ret_val) : ret_val
260
260
  }
261
261
 
@@ -348,18 +348,18 @@ export default class Navgo {
348
348
  if (nav_id !== this.#nav_active) return
349
349
 
350
350
  //
351
- // loaders
351
+ // loader
352
352
  //
353
353
  let data
354
354
  if (hit) {
355
355
  const pre = this.#preloads.get(path)
356
356
  data =
357
357
  pre?.data ??
358
- (await (pre?.promise || this.#run_loaders(hit.route, hit.params)).catch(e => ({
358
+ (await (pre?.promise || this.#run_loader(hit.route, hit.params)).catch(e => ({
359
359
  __error: e,
360
360
  })))
361
361
  this.#preloads.delete(path)
362
- ℹ('[🧭 loaders]', pre ? 'using preloaded data' : 'loaded', {
362
+ ℹ('[🧭 loader]', pre ? 'using preloaded data' : 'loaded', {
363
363
  path,
364
364
  preloaded: !!pre,
365
365
  has_error: !!data?.__error,
@@ -409,6 +409,8 @@ export default class Navgo {
409
409
  },
410
410
  event: ev_param,
411
411
  })
412
+ this.route.set(this.#current)
413
+
412
414
  // await so that apply_scroll is after potential async work
413
415
  await this.#opts.after_navigate?.(nav)
414
416
 
@@ -424,12 +426,11 @@ export default class Navgo {
424
426
  await this.#opts.tick?.()
425
427
 
426
428
  this.#apply_scroll(nav)
427
- this.route.set(this.#current)
428
- if (nav_id === this.#nav_active) this.is_navigating.set(false)
429
+ this.is_navigating.set(false)
429
430
  }
430
431
 
431
432
  /**
432
- * Shallow push — updates the URL/state but DOES NOT call handlers or loaders.
433
+ * Shallow push — updates the URL/state but DOES NOT call handlers or loader.
433
434
  */
434
435
  #commit_shallow(url, state, replace) {
435
436
  const u = new URL(url || location.href, location.href)
@@ -476,7 +477,7 @@ export default class Navgo {
476
477
  }
477
478
 
478
479
  /**
479
- * Preload loaders for a URL (e.g. to prime cache).
480
+ * Preload loader data for a URL (e.g. to prime cache).
480
481
  * Dedupes concurrent preloads for the same path.
481
482
  */
482
483
  /** @param {string} url_raw @returns {Promise<unknown|void>} */
@@ -504,7 +505,7 @@ export default class Navgo {
504
505
  }
505
506
 
506
507
  const entry = {}
507
- entry.promise = this.#run_loaders(hit.route, hit.params).then(data => {
508
+ entry.promise = this.#run_loader(hit.route, hit.params).then(data => {
508
509
  entry.data = data
509
510
  delete entry.promise
510
511
  ℹ('[🧭 preload]', 'done', { path })
@@ -634,6 +635,7 @@ export default class Navgo {
634
635
  removeEventListener('hashchange', this.#on_hashchange)
635
636
  removeEventListener('scroll', this.#scroll_handler, { capture: true })
636
637
  this.#areas_pos.clear()
638
+ delete window.navgo
637
639
  }
638
640
 
639
641
  #clear_onward_history() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "navgo",
3
- "version": "3.0.8",
3
+ "version": "4.0.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/mustafa0x/navgo.git"
package/readme.md CHANGED
@@ -24,7 +24,7 @@ const routes = [
24
24
  /* id: Navgo.validators.int({ min: 1 }) */
25
25
  },
26
26
  // load data before URL changes; result goes to after_navigate(...)
27
- loaders: params => fetch('/api/admin').then(r => r.json()),
27
+ loader: params => fetch('/api/admin').then(r => r.json()),
28
28
  // per-route guard; cancel synchronously to block nav
29
29
  before_route_leave(nav) {
30
30
  if ((nav.type === 'link' || nav.type === 'nav') && !confirm('Enter admin?')) {
@@ -39,7 +39,7 @@ const routes = [
39
39
  const router = new Navgo(routes, {
40
40
  base: '/',
41
41
  before_navigate(nav) {
42
- // app-level hook before loaders/URL update; may cancel
42
+ // app-level hook before loader/URL update; may cancel
43
43
  console.log('before_navigate', nav.type, '→', nav.to?.url.pathname)
44
44
  },
45
45
  after_navigate(nav) {
@@ -97,7 +97,7 @@ Notes:
97
97
  - `base`: `string` (default `'/'`)
98
98
  - App base pathname. With or without leading/trailing slashes is accepted.
99
99
  - `before_navigate`: `(nav: Navigation) => void`
100
- - App-level hook called once per navigation attempt after the per-route guard and before loaders/URL update. May call `nav.cancel()` synchronously to prevent navigation.
100
+ - App-level hook called once per navigation attempt after the per-route guard and before loader/URL update. May call `nav.cancel()` synchronously to prevent navigation.
101
101
  - `after_navigate`: `(nav: Navigation) => void`
102
102
  - App-level hook called after routing completes (URL updated, data loaded). `nav.to.data` holds any loader data.
103
103
  - `tick`: `() => void | Promise<void>`
@@ -139,7 +139,7 @@ const {route, is_navigating} = router
139
139
 
140
140
  - param_validators?: `Record<string, (value: string|null|undefined) => boolean>`
141
141
  - Validate params (e.g., `id: Navgo.validators.int({ min: 1 })`). Any `false` result skips the route.
142
- - loaders?(params): `unknown | Promise | Array<unknown|Promise>`
142
+ - loader?(params): `unknown | Promise | Array<unknown|Promise>`
143
143
  - Run before URL changes on `link`/`nav`. Results are cached per formatted path and forwarded to `after_navigate`.
144
144
  - validate?(params): `boolean | Promise<boolean>`
145
145
  - Predicate called during matching. If it returns or resolves to `false`, the route is skipped.
@@ -178,7 +178,7 @@ const routes = [
178
178
  param_validators: {
179
179
  /* ... */
180
180
  },
181
- loaders: params => fetch('/api/admin/stats').then(r => r.json()),
181
+ loader: params => fetch('/api/admin/stats').then(r => r.json()),
182
182
  before_route_leave(nav) {
183
183
  if (nav.type === 'link' || nav.type === 'nav') {
184
184
  if (!confirm('Enter admin area?')) nav.cancel()
@@ -218,7 +218,7 @@ The path to format.
218
218
 
219
219
  Returns: `Promise<void>`
220
220
 
221
- Runs any matching route `loaders` before updating the URL and then updates history. Route processing triggers `after_navigate`. Use `replace: true` to replace the current history entry.
221
+ Runs any matching route `loader` before updating the URL and then updates history. Route processing triggers `after_navigate`. Use `replace: true` to replace the current history entry.
222
222
 
223
223
  #### uri
224
224
 
@@ -284,8 +284,8 @@ Or with a custom id:
284
284
 
285
285
  Returns: `Promise<unknown | void>`
286
286
 
287
- Preload a route's `loaders` data for a given `uri` without navigating. Concurrent calls for the same path are deduped.
288
- Note: Resolves to `undefined` when the matched route has no `loaders`.
287
+ Preload a route's `loader` data for a given `uri` without navigating. Concurrent calls for the same path are deduped.
288
+ Note: Resolves to `undefined` when the matched route has no `loader`.
289
289
 
290
290
  ### push_state(url?, state?)
291
291
 
@@ -335,7 +335,7 @@ For `link` and `goto` navigations that match a route:
335
335
  → before_route_leave({ type }) // per-route guard
336
336
  → before_navigate(nav) // app-level start
337
337
  → cancelled? yes → stop
338
- → no → run loaders(params) // may be value, Promise, or Promise[]
338
+ → no → run loader(params) // may be value, Promise, or Promise[]
339
339
  → cache data by formatted path
340
340
  → history.push/replaceState(new URL)
341
341
  → after_navigate(nav)
@@ -344,7 +344,7 @@ For `link` and `goto` navigations that match a route:
344
344
  ```
345
345
 
346
346
  - If a loader throws/rejects, navigation continues and `after_navigate(..., with nav.to.data = { __error })` is delivered so UI can render an error state.
347
- - For `popstate`, loaders run before completion so content matches the target entry; this improves scroll restoration. Errors are delivered via `after_navigate` with `nav.to.data = { __error }`.
347
+ - For `popstate`, the route's `loader` runs before completion so content matches the target entry; this improves scroll restoration. Errors are delivered via `after_navigate` with `nav.to.data = { __error }`.
348
348
 
349
349
  ### Shallow Routing
350
350
 
@@ -384,10 +384,10 @@ scroll flow
384
384
 
385
385
  - `format(uri)` -- normalizes a path relative to `base`. Returns `false` when `uri` is outside of `base`.
386
386
  - `match(uri)` -- returns a Promise of `{ route, params } | null` using string/RegExp patterns and validators. Awaits an async `validate(params)` if provided.
387
- - `goto(uri, { replace? })` -- fires route-level `before_route_leave('goto')`, calls global `before_navigate`, saves scroll, runs loaders, pushes/replaces, and completes via `after_navigate`.
387
+ - `goto(uri, { replace? })` -- fires route-level `before_route_leave('goto')`, calls global `before_navigate`, saves scroll, runs loader, pushes/replaces, and completes via `after_navigate`.
388
388
  - `init()` -- wires global listeners (`popstate`, `pushstate`, `replacestate`, click) and optional hover/tap preloading; immediately processes the current location.
389
389
  - `destroy()` -- removes listeners added by `init()`.
390
- - `preload(uri)` -- pre-executes a route's `loaders` for a path and caches the result; concurrent calls are deduped.
390
+ - `preload(uri)` -- pre-executes a route's `loader` for a path and caches the result; concurrent calls are deduped.
391
391
  - `push_state(url?, state?)` -- shallow push that updates the URL and `history.state` without route processing.
392
392
  - `replace_state(url?, state?)` -- shallow replace that updates the URL and `history.state` without route processing.
393
393