@@ -7,8 +7,6 @@ import { useContext, useMemo, useReducer, useLayoutEffect, useRef } from 'preact
7
7
* @typedef {import('./internal.d.ts').VNode } VNode
8
8
*/
9
9
10
- /** @type {boolean } */
11
- let push ;
12
10
/** @type {string | RegExp | undefined } */
13
11
let scope ;
14
12
@@ -23,45 +21,23 @@ function isInScope(href) {
23
21
) ;
24
22
}
25
23
24
+
26
25
/**
27
26
* @param {string } state
28
- * @param {MouseEvent | PopStateEvent | { url: string, replace?: boolean } } action
27
+ * @param {NavigateEvent } e
29
28
*/
30
- function handleNav ( state , action ) {
31
- let url = '' ;
32
- push = undefined ;
33
- if ( action && action . type === 'click' ) {
34
- // ignore events the browser takes care of already:
35
- if ( action . ctrlKey || action . metaKey || action . altKey || action . shiftKey || action . button !== 0 ) {
36
- return state ;
37
- }
38
-
39
- const link = action . composedPath ( ) . find ( el => el . nodeName == 'A' && el . href ) ,
40
- href = link && link . getAttribute ( 'href' ) ;
41
- if (
42
- ! link ||
43
- link . origin != location . origin ||
44
- / ^ # / . test ( href ) ||
45
- ! / ^ ( _ ? s e l f ) ? $ / i. test ( link . target ) ||
46
- ! isInScope ( href )
47
- ) {
48
- return state ;
49
- }
29
+ function handleNav ( state , e ) {
30
+ if ( ! e . canIntercept ) return state ;
31
+ if ( e . hashChange || e . downloadRequest !== null ) return state ;
50
32
51
- push = true ;
52
- action . preventDefault ( ) ;
53
- url = link . href . replace ( location . origin , '' ) ;
54
- } else if ( action && action . url ) {
55
- push = ! action . replace ;
56
- url = action . url ;
57
- } else {
58
- url = location . pathname + location . search ;
33
+ const url = new URL ( e . destination . url ) ;
34
+ if ( ! isInScope ( url . href ) ) {
35
+ return state ;
59
36
}
60
37
61
- if ( push === true ) history . pushState ( null , '' , url ) ;
62
- else if ( push === false ) history . replaceState ( null , '' , url ) ;
63
- return url ;
64
- } ;
38
+ e . intercept ( ) ;
39
+ return url . href . replace ( url . origin , '' ) ;
40
+ }
65
41
66
42
export const exec = ( url , route , matches = { } ) => {
67
43
url = url . split ( '/' ) . filter ( Boolean ) ;
@@ -99,7 +75,6 @@ export const exec = (url, route, matches = {}) => {
99
75
export function LocationProvider ( props ) {
100
76
const [ url , route ] = useReducer ( handleNav , location . pathname + location . search ) ;
101
77
if ( props . scope ) scope = props . scope ;
102
- const wasPush = push === true ;
103
78
104
79
const value = useMemo ( ( ) => {
105
80
const u = new URL ( url , location . origin ) ;
@@ -110,18 +85,14 @@ export function LocationProvider(props) {
110
85
path,
111
86
pathParams : { } ,
112
87
searchParams : Object . fromEntries ( u . searchParams ) ,
113
- route : ( url , replace ) => route ( { url, replace } ) ,
114
- wasPush
115
88
} ;
116
89
} , [ url ] ) ;
117
90
118
91
useLayoutEffect ( ( ) => {
119
- addEventListener ( 'click' , route ) ;
120
- addEventListener ( 'popstate' , route ) ;
92
+ navigation . addEventListener ( 'navigate' , route ) ;
121
93
122
94
return ( ) => {
123
- removeEventListener ( 'click' , route ) ;
124
- removeEventListener ( 'popstate' , route ) ;
95
+ navigation . removeEventListener ( 'navigate' , route ) ;
125
96
} ;
126
97
} , [ ] ) ;
127
98
@@ -133,7 +104,7 @@ const RESOLVED = Promise.resolve();
133
104
export function Router ( props ) {
134
105
const [ c , update ] = useReducer ( c => c + 1 , 0 ) ;
135
106
136
- const { url, path, pathParams, searchParams, wasPush } = useLocation ( ) ;
107
+ const { url, path, pathParams, searchParams } = useLocation ( ) ;
137
108
if ( ! url ) {
138
109
throw new Error ( `preact-iso's <Router> must be used within a <LocationProvider>, see: https://github.com/preactjs/preact-iso#locationprovider` ) ;
139
110
}
@@ -257,15 +228,15 @@ export function Router(props) {
257
228
258
229
// The route is loaded and rendered.
259
230
if ( prevRoute . current !== path ) {
260
- if ( wasPush ) scrollTo ( 0 , 0 ) ;
231
+ scrollTo ( 0 , 0 ) ;
261
232
if ( props . onRouteChange ) props . onRouteChange ( url ) ;
262
233
263
234
prevRoute . current = path ;
264
235
}
265
236
266
237
if ( props . onLoadEnd && isLoading . current ) props . onLoadEnd ( url ) ;
267
238
isLoading . current = false ;
268
- } , [ path , wasPush , c ] ) ;
239
+ } , [ path , c ] ) ;
269
240
270
241
// Note: cur MUST render first in order to set didSuspend & prev.
271
242
return routeChanged
@@ -282,7 +253,7 @@ const RenderRef = ({ r }) => r.current;
282
253
Router . Provider = LocationProvider ;
283
254
284
255
LocationProvider . ctx = createContext (
285
- /** @type {import('./router.d.ts').LocationHook & { wasPush: boolean } } */ ( { } )
256
+ /** @type {import('./router.d.ts').LocationHook }} */ ( { } )
286
257
) ;
287
258
const RouterContext = createContext (
288
259
/** @type {{ rest: string } } */ ( { } )
0 commit comments