1
1
import { h , createContext , cloneElement , toChildArray } from 'preact' ;
2
2
import { useContext , useMemo , useReducer , useLayoutEffect , useRef } from 'preact/hooks' ;
3
3
4
+ /**
5
+ * @template T
6
+ * @typedef {import('preact').RefObject<T> } RefObject
7
+ * @typedef {import('./internal.d.ts').VNode } VNode
8
+ */
9
+
4
10
let push ;
5
11
const UPDATE = ( state , url ) => {
6
12
push = undefined ;
@@ -96,6 +102,7 @@ export function LocationProvider(props) {
96
102
}
97
103
98
104
const RESOLVED = Promise . resolve ( ) ;
105
+ /** @this {import('./internal.d.ts').AugmentedComponent} */
99
106
export function Router ( props ) {
100
107
const [ c , update ] = useReducer ( c => c + 1 , 0 ) ;
101
108
@@ -107,27 +114,28 @@ export function Router(props) {
107
114
// Monotonic counter used to check if an un-suspending route is still the current route:
108
115
const count = useRef ( 0 ) ;
109
116
// The current route:
110
- const cur = useRef ( ) ;
117
+ const cur = /** @type { RefObject<VNode<any>> } */ ( useRef ( ) ) ;
111
118
// Previous route (if current route is suspended):
112
- const prev = useRef ( ) ;
119
+ const prev = /** @type { RefObject<VNode<any>> } */ ( useRef ( ) ) ;
113
120
// A not-yet-hydrated DOM root to remove once we commit:
114
- const pendingBase = useRef ( ) ;
121
+ const pendingBase = /** @type { RefObject<Element | Text> } */ ( useRef ( ) ) ;
115
122
// has this component ever successfully rendered without suspending:
116
123
const hasEverCommitted = useRef ( false ) ;
117
124
// was the most recent render successful (did not suspend):
118
- const didSuspend = useRef ( ) ;
125
+ const didSuspend = /** @type { RefObject<boolean> } */ ( useRef ( ) ) ;
119
126
didSuspend . current = false ;
120
127
// has the route component changed
121
128
const routeChanged = useRef ( false ) ;
122
129
123
- let pr , d , m ;
124
- toChildArray ( props . children ) . some ( vnode => {
125
- const matches = exec ( rest , vnode . props . path , ( m = { ...vnode . props , path : rest , query, params, rest : '' } ) ) ;
126
- if ( matches ) return ( pr = cloneElement ( vnode , m ) ) ;
127
- if ( vnode . props . default ) d = cloneElement ( vnode , m ) ;
130
+ let pathRoute , defaultRoute , matchProps ;
131
+ toChildArray ( props . children ) . some ( ( /** @type { VNode<any> } */ vnode ) => {
132
+ const matches = exec ( rest , vnode . props . path , ( matchProps = { ...vnode . props , path : rest , query, params, rest : '' } ) ) ;
133
+ if ( matches ) return ( pathRoute = cloneElement ( vnode , matchProps ) ) ;
134
+ if ( vnode . props . default ) defaultRoute = cloneElement ( vnode , matchProps ) ;
128
135
} ) ;
129
136
130
- let incoming = pr || d ;
137
+ /** @type {VNode<any> | undefined } */
138
+ let incoming = pathRoute || defaultRoute ;
131
139
useMemo ( ( ) => {
132
140
prev . current = cur . current ;
133
141
@@ -143,7 +151,8 @@ export function Router(props) {
143
151
144
152
const isHydratingSuspense = cur . current && cur . current . __u & MODE_HYDRATE && cur . current . __u & MODE_SUSPENDED ;
145
153
const isHydratingBool = cur . current && cur . current . __h ;
146
- cur . current = h ( RouteContext . Provider , { value : m } , incoming ) ;
154
+ // @ts -ignore
155
+ cur . current = /** @type {VNode<any> } */ ( h ( RouteContext . Provider , { value : matchProps } , incoming ) ) ;
147
156
if ( isHydratingSuspense ) {
148
157
cur . current . __u |= MODE_HYDRATE ;
149
158
cur . current . __u |= MODE_SUSPENDED ;
@@ -242,10 +251,12 @@ const RenderRef = ({ r }) => r.current;
242
251
243
252
Router . Provider = LocationProvider ;
244
253
245
- /** @typedef {{ url: string, path: string, query: object, route, wasPush: boolean } } RouteInfo */
246
-
247
- LocationProvider . ctx = createContext ( /** @type {RouteInfo } */ ( { } ) ) ;
248
- const RouteContext = createContext ( { } ) ;
254
+ LocationProvider . ctx = createContext (
255
+ /** @type {import('./router.d.ts').LocationHook & { wasPush: boolean } } */ ( { } )
256
+ ) ;
257
+ const RouteContext = createContext (
258
+ /** @type {import('./router.d.ts').RouteHook & { rest: string } } */ ( { } )
259
+ ) ;
249
260
250
261
export const Route = props => h ( props . component , props ) ;
251
262
0 commit comments