@@ -7,46 +7,30 @@ import { useContext, useMemo, useReducer, useLayoutEffect, useRef } from 'preact
7
7
* @typedef {import('./internal.d.ts').VNode } VNode
8
8
*/
9
9
10
- let push , scope ;
11
- const UPDATE = ( state , url ) => {
12
- push = undefined ;
13
- if ( url && url . type === 'click' ) {
14
- // ignore events the browser takes care of already:
15
- if ( url . ctrlKey || url . metaKey || url . altKey || url . shiftKey || url . button !== 0 ) {
16
- return state ;
17
- }
18
-
19
- const link = url . target . closest ( 'a[href]' ) ,
20
- href = link && link . getAttribute ( 'href' ) ;
21
- if (
22
- ! link ||
23
- link . origin != location . origin ||
24
- / ^ # / . test ( href ) ||
25
- ! / ^ ( _ ? s e l f ) ? $ / i. test ( link . target ) ||
26
- scope && ( typeof scope == 'string'
27
- ? ! href . startsWith ( scope )
28
- : ! scope . test ( href )
29
- )
30
- ) {
31
- return state ;
32
- }
10
+ /** @type {string | RegExp | undefined } */
11
+ let scope ;
33
12
34
- push = true ;
35
- url . preventDefault ( ) ;
36
- url = link . href . replace ( location . origin , '' ) ;
37
- } else if ( typeof url === 'string' ) {
38
- push = true ;
39
- } else if ( url && url . url ) {
40
- push = ! url . replace ;
41
- url = url . url ;
42
- } else {
43
- url = location . pathname + location . search ;
13
+ /**
14
+ * @param {string } state
15
+ * @param {NavigateEvent } e
16
+ */
17
+ function handleNav ( state , e ) {
18
+ if ( ! e . canIntercept ) return state ;
19
+ if ( e . hashChange || e . downloadRequest !== null ) return state ;
20
+
21
+ const url = new URL ( e . destination . url ) ;
22
+ if (
23
+ scope && ( typeof scope == 'string'
24
+ ? ! url . pathname . startsWith ( scope )
25
+ : ! scope . test ( url . pathname )
26
+ )
27
+ ) {
28
+ return state ;
44
29
}
45
30
46
- if ( push === true ) history . pushState ( null , '' , url ) ;
47
- else if ( push === false ) history . replaceState ( null , '' , url ) ;
48
- return url ;
49
- } ;
31
+ e . intercept ( ) ;
32
+ return url . href . replace ( url . origin , '' ) ;
33
+ }
50
34
51
35
export const exec = ( url , route , matches = { } ) => {
52
36
url = url . split ( '/' ) . filter ( Boolean ) ;
@@ -80,9 +64,8 @@ export const exec = (url, route, matches = {}) => {
80
64
* @type {import('./router.d.ts').LocationProvider }
81
65
*/
82
66
export function LocationProvider ( props ) {
83
- const [ url , route ] = useReducer ( UPDATE , location . pathname + location . search ) ;
67
+ const [ url , route ] = useReducer ( handleNav , location . pathname + location . search ) ;
84
68
if ( props . scope ) scope = props . scope ;
85
- const wasPush = push === true ;
86
69
87
70
const value = useMemo ( ( ) => {
88
71
const u = new URL ( url , location . origin ) ;
@@ -93,18 +76,14 @@ export function LocationProvider(props) {
93
76
path,
94
77
pathParams : { } ,
95
78
searchParams : Object . fromEntries ( u . searchParams ) ,
96
- route : ( url , replace ) => route ( { url, replace } ) ,
97
- wasPush
98
79
} ;
99
80
} , [ url ] ) ;
100
81
101
82
useLayoutEffect ( ( ) => {
102
- addEventListener ( 'click' , route ) ;
103
- addEventListener ( 'popstate' , route ) ;
83
+ navigation . addEventListener ( 'navigate' , route ) ;
104
84
105
85
return ( ) => {
106
- removeEventListener ( 'click' , route ) ;
107
- removeEventListener ( 'popstate' , route ) ;
86
+ navigation . removeEventListener ( 'navigate' , route ) ;
108
87
} ;
109
88
} , [ ] ) ;
110
89
@@ -116,7 +95,7 @@ const RESOLVED = Promise.resolve();
116
95
export function Router ( props ) {
117
96
const [ c , update ] = useReducer ( c => c + 1 , 0 ) ;
118
97
119
- const { url, path, pathParams, searchParams, wasPush } = useLocation ( ) ;
98
+ const { url, path, pathParams, searchParams } = useLocation ( ) ;
120
99
const { rest = path } = useContext ( RouterContext ) ;
121
100
122
101
const isLoading = useRef ( false ) ;
@@ -237,15 +216,15 @@ export function Router(props) {
237
216
238
217
// The route is loaded and rendered.
239
218
if ( prevRoute . current !== path ) {
240
- if ( wasPush ) scrollTo ( 0 , 0 ) ;
219
+ scrollTo ( 0 , 0 ) ;
241
220
if ( props . onRouteChange ) props . onRouteChange ( url ) ;
242
221
243
222
prevRoute . current = path ;
244
223
}
245
224
246
225
if ( props . onLoadEnd && isLoading . current ) props . onLoadEnd ( url ) ;
247
226
isLoading . current = false ;
248
- } , [ path , wasPush , c ] ) ;
227
+ } , [ path , c ] ) ;
249
228
250
229
// Note: cur MUST render first in order to set didSuspend & prev.
251
230
return routeChanged
@@ -262,7 +241,7 @@ const RenderRef = ({ r }) => r.current;
262
241
Router . Provider = LocationProvider ;
263
242
264
243
LocationProvider . ctx = createContext (
265
- /** @type {import('./router.d.ts').LocationHook & { wasPush: boolean } } */ ( { } )
244
+ /** @type {import('./router.d.ts').LocationHook }} */ ( { } )
266
245
) ;
267
246
const RouterContext = createContext (
268
247
/** @type {{ rest: string } } */ ( { } )
0 commit comments