1 | import type {
|
2 | NavigationContainerRefWithCurrent,
|
3 | NavigationState,
|
4 | PartialState,
|
5 | } from '@react-navigation/core'
|
6 | import type { ReactNode } from 'react'
|
7 | import type { TextProps, GestureResponderEvent } from 'react-native'
|
8 |
|
9 | export namespace OneRouter {
|
10 | export interface __routes<T extends string = string> extends Record<string, unknown> {}
|
11 |
|
12 |
|
13 | export type Route<Path> = {
|
14 | Params: InputRouteParams<Path>
|
15 | Props: { params: InputRouteParams<Path> }
|
16 | Loader: (props: { params: InputRouteParams<Path> }) => any
|
17 | }
|
18 |
|
19 | type StaticRoutes = __routes extends { StaticRoutes: string } ? __routes['StaticRoutes'] : string
|
20 |
|
21 | type DynamicRoutes<T extends string> = __routes<T> extends { DynamicRoutes: any }
|
22 | ? T extends __routes<infer _>['DynamicRoutes']
|
23 | ? T
|
24 | : never
|
25 | : string
|
26 |
|
27 | export type DynamicRouteTemplate = __routes extends { DynamicRouteTemplate: string }
|
28 | ? __routes['DynamicRouteTemplate']
|
29 | : string
|
30 |
|
31 | export type NavigationRef = NavigationContainerRefWithCurrent<ReactNavigation.RootParamList>
|
32 |
|
33 | export type RelativePathString = `./${string}` | `../${string}` | '..'
|
34 | export type AbsoluteRoute = DynamicRouteTemplate | StaticRoutes
|
35 | export type ExternalPathString = `${string}:${string}`
|
36 | export type OneRouterRoutes = DynamicRouteTemplate | StaticRoutes | RelativePathString
|
37 | export type AllRoutes = OneRouterRoutes | ExternalPathString
|
38 |
|
39 | export type LinkToOptions = {
|
40 | scroll?: boolean
|
41 | }
|
42 |
|
43 | type SearchOrHash = `?${string}` | `#${string}`
|
44 |
|
45 | export type UnknownInputParams = Record<
|
46 | string,
|
47 | string | number | undefined | null | (string | number)[]
|
48 | >
|
49 |
|
50 | type UnknownOutputParams = Record<string, string | string[]>
|
51 |
|
52 | |
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 | export type SingleRoutePart<S extends string> = S extends `${string}/${string}`
|
65 | ? never
|
66 | : S extends `${string}${SearchOrHash}`
|
67 | ? never
|
68 | : S extends ''
|
69 | ? never
|
70 | : S extends `(${string})`
|
71 | ? never
|
72 | : S extends `[${string}]`
|
73 | ? never
|
74 | : S
|
75 |
|
76 | |
77 |
|
78 |
|
79 | export type CatchAllRoutePart<S extends string> = S extends `${string}${SearchOrHash}`
|
80 | ? never
|
81 | : S extends ''
|
82 | ? never
|
83 | : S extends `${string}(${string})${string}`
|
84 | ? never
|
85 | : S extends `${string}[${string}]${string}`
|
86 | ? never
|
87 | : S
|
88 |
|
89 | |
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 | type IsParameter<Part> = Part extends `[${infer ParamName}]` ? ParamName : never
|
96 |
|
97 | |
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | type ParameterNames<Path> = Path extends `${infer PartA}/${infer PartB}`
|
106 | ? IsParameter<PartA> | ParameterNames<PartB>
|
107 | : IsParameter<Path>
|
108 |
|
109 | |
110 |
|
111 |
|
112 |
|
113 |
|
114 | type RouteSegments<Path> = Path extends `${infer PartA}/${infer PartB}`
|
115 | ? PartA extends '' | '.'
|
116 | ? [...RouteSegments<PartB>]
|
117 | : [PartA, ...RouteSegments<PartB>]
|
118 | : Path extends ''
|
119 | ? []
|
120 | : [Path]
|
121 |
|
122 | type AllUngroupedRoutes<Path> = Path extends `(${infer PartA})/${infer PartB}`
|
123 | ? `(${PartA})/${AllUngroupedRoutes<PartB>}` | AllUngroupedRoutes<PartB>
|
124 | : Path
|
125 |
|
126 | |
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 | export type InputRouteParams<Path> = {
|
136 | [Key in ParameterNames<Path> as Key extends `...${infer Name}`
|
137 | ? Name
|
138 | : Key]: Key extends `...${string}` ? string[] : string
|
139 | }
|
140 |
|
141 |
|
142 |
|
143 | type OutputRouteParams<Path> = {
|
144 | [Key in ParameterNames<Path> as Key extends `...${infer Name}`
|
145 | ? Name
|
146 | : Key]: Key extends `...${string}` ? string[] : string
|
147 | } & UnknownOutputParams
|
148 |
|
149 | |
150 |
|
151 |
|
152 | export type SearchParams<T extends AllRoutes = never> = T extends DynamicRouteTemplate
|
153 | ? OutputRouteParams<T>
|
154 | : T extends StaticRoutes
|
155 | ? never
|
156 | : UnknownOutputParams
|
157 |
|
158 | |
159 |
|
160 |
|
161 |
|
162 | export type DynamicRoutesHref = DynamicRouteString<{ __branded__: any }, DynamicRouteTemplate>
|
163 | export type DynamicRoutesHref2 = DynamicRouteString<string, DynamicRouteTemplate>
|
164 |
|
165 | |
166 |
|
167 |
|
168 | export type Href<T extends string | object = { __branded__: any }> =
|
169 | | StringRouteToType<AllUngroupedRoutes<StaticRoutes> | RelativePathString | ExternalPathString>
|
170 | | DynamicRouteString<T, DynamicRouteTemplate>
|
171 | | DynamicRouteObject<
|
172 | StaticRoutes | RelativePathString | ExternalPathString | DynamicRouteTemplate
|
173 | >
|
174 |
|
175 | type StringRouteToType<T extends string> =
|
176 | | T
|
177 | | `${T}${SearchOrHash}`
|
178 | | { pathname: T; params?: UnknownInputParams | never }
|
179 |
|
180 | |
181 |
|
182 |
|
183 | type DynamicRouteString<
|
184 | T extends string | object,
|
185 | P = DynamicRouteTemplate,
|
186 | > = '__branded__' extends keyof T
|
187 | ? DynamicTemplateToHrefString<P>
|
188 | : T extends string
|
189 | ? DynamicRoutes<T>
|
190 | : never
|
191 |
|
192 | type DynamicTemplateToHrefString<Path> = Path extends `${infer PartA}/${infer PartB}`
|
193 | ?
|
194 | `${PartA extends `[${string}]` ? string : PartA}/${DynamicTemplateToHrefString<PartB>}`
|
195 | : // Path is the last segment.
|
196 | Path extends `[${string}]`
|
197 | ? string
|
198 | : Path
|
199 |
|
200 | type DynamicRouteObject<T> = T extends DynamicRouteTemplate
|
201 | ? {
|
202 | pathname: T
|
203 | params: InputRouteParams<T>
|
204 | }
|
205 | : never
|
206 |
|
207 | export type LoadingState = 'loading' | 'loaded'
|
208 |
|
209 | export type ResultState = PartialState<NavigationState> & {
|
210 | state?: ResultState
|
211 | linkOptions?: OneRouter.LinkToOptions
|
212 | }
|
213 |
|
214 | export type RootStateListener = (state: ResultState) => void
|
215 | export type LoadingStateListener = (state: LoadingState) => void
|
216 |
|
217 | /***********************
|
218 | * One Exports *
|
219 | ***********************/
|
220 |
|
221 | export type InputRouteParamsBlank = Record<string, string | undefined | null>
|
222 | export type InpurRouteParamsGeneric = InputRouteParamsBlank | InputRouteParams<any>
|
223 |
|
224 | export type Router = {
|
225 | /** Go back in the history. */
|
226 | back: () => void
|
227 | /** If there's history that supports invoking the `back` function. */
|
228 | canGoBack: () => boolean
|
229 | /** Navigate to the provided href using a push operation if possible. */
|
230 | push: (href: Href, options?: LinkToOptions) => void
|
231 | /** Navigate to the provided href. */
|
232 | navigate: (href: Href, options?: LinkToOptions) => void
|
233 | /** Navigate to route without appending to the history. */
|
234 | replace: (href: Href, options?: LinkToOptions) => void
|
235 | /** Navigate to the provided href using a push operation if possible. */
|
236 | dismiss: (count?: number) => void
|
237 | /** Navigate to first screen within the lowest stack. */
|
238 | dismissAll: () => void
|
239 | /** If there's history that supports invoking the `dismiss` and `dismissAll` function. */
|
240 | canDismiss: () => boolean
|
241 | /** Update the current route query params. */
|
242 | setParams: <T = ''>(params?: T extends '' ? InputRouteParamsBlank : InputRouteParams<T>) => void
|
243 | /** Subscribe to state updates from the router */
|
244 | subscribe: (listener: RootStateListener) => () => void
|
245 | /** Subscribe to loading state updates */
|
246 | onLoadState: (listener: LoadingStateListener) => () => void
|
247 | }
|
248 |
|
249 | /** The imperative router. */
|
250 | export declare const router: Router
|
251 |
|
252 | /************
|
253 | * <Link /> *
|
254 | ************/
|
255 | export interface WebAnchorProps {
|
256 | /**
|
257 | * **Web only:** Specifies where to open the `href`.
|
258 | *
|
259 | * - **_self**: the current tab.
|
260 | * - **_blank**: opens in a new tab or window.
|
261 | * - **_parent**: opens in the parent browsing context. If no parent, defaults to **_self**.
|
262 | * - **_top**: opens in the highest browsing context ancestor. If no ancestors, defaults to **_self**.
|
263 | *
|
264 | * This property is passed to the underlying anchor (`<a>`) tag.
|
265 | *
|
266 | * @default '_self'
|
267 | *
|
268 | * @example
|
269 | * <Link href="https://expo.dev" target="_blank">Go to Expo in new tab</Link>
|
270 | */
|
271 | target?: '_self' | '_blank' | '_parent' | '_top' | (string & object)
|
272 |
|
273 | /**
|
274 | * **Web only:** Specifies the relationship between the `href` and the current route.
|
275 | *
|
276 | * Common values:
|
277 | * - **nofollow**: Indicates to search engines that they should not follow the `href`. This is often used for user-generated content or links that should not influence search engine rankings.
|
278 | * - **noopener**: Suggests that the `href` should not have access to the opening window's `window.opener` object, which is a security measure to prevent potentially harmful behavior in cases of links that open new tabs or windows.
|
279 | * - **noreferrer**: Requests that the browser not send the `Referer` HTTP header when navigating to the `href`. This can enhance user privacy.
|
280 | *
|
281 | * The `rel` property is primarily used for informational and instructive purposes, helping browsers and web
|
282 | * crawlers make better decisions about how to handle and interpret the links on a web page. It is important
|
283 | * to use appropriate `rel` values to ensure that links behave as intended and adhere to best practices for web
|
284 | * development and SEO (Search Engine Optimization).
|
285 | *
|
286 | * This property is passed to the underlying anchor (`<a>`) tag.
|
287 | *
|
288 | * @example
|
289 | * <Link href="https://expo.dev" rel="nofollow">Go to Expo</Link>
|
290 | */
|
291 | rel?: string
|
292 |
|
293 | /**
|
294 | * **Web only:** Specifies that the `href` should be downloaded when the user clicks on the link,
|
295 | * instead of navigating to it. It is typically used for links that point to files that the user should download,
|
296 | * such as PDFs, images, documents, etc.
|
297 | *
|
298 | * The value of the `download` property, which represents the filename for the downloaded file.
|
299 | * This property is passed to the underlying anchor (`<a>`) tag.
|
300 | *
|
301 | * @example
|
302 | * <Link href="/image.jpg" download="my-image.jpg">Download image</Link>
|
303 | */
|
304 | download?: string
|
305 | }
|
306 |
|
307 | export interface LinkProps<T extends string | object>
|
308 | extends Omit<TextProps, 'href'>,
|
309 | WebAnchorProps {
|
310 | /** Path to route to. */
|
311 | href: Href<T>
|
312 |
|
313 | // TODO: This may need to be extracted for React Native style support.
|
314 | /** Forward props to child component. Useful for custom buttons. */
|
315 | asChild?: boolean
|
316 |
|
317 | /** Should replace the current route without adding to the history. */
|
318 | replace?: boolean
|
319 | /** Should push the current route */
|
320 | push?: boolean
|
321 |
|
322 | /** On web, this sets the HTML `class` directly. On native, this can be used with CSS interop tools like Nativewind. */
|
323 | className?: string
|
324 |
|
325 | onPress?: (e: React.MouseEvent<HTMLAnchorElement, MouseEvent> | GestureResponderEvent) => void
|
326 | }
|
327 |
|
328 | export interface LinkComponent {
|
329 | <T extends string | object>(props: React.PropsWithChildren<LinkProps<T>>): JSX.Element
|
330 | /** Helper method to resolve an Href object into a string. */
|
331 | resolveHref: (href: Href) => string
|
332 | }
|
333 |
|
334 | /**
|
335 | * Component to render link to another route using a path.
|
336 | * Uses an anchor tag on the web.
|
337 | *
|
338 | * @param props.href Absolute path to route (e.g. \`/feeds/hot\`).
|
339 | * @param props.replace Should replace the current route without adding to the history.
|
340 | * @param props.asChild Forward props to child component. Useful for custom buttons.
|
341 | * @param props.children Child elements to render the content.
|
342 | * @param props.className On web, this sets the HTML \`class\` directly. On native, this can be used with CSS interop tools like Nativewind.
|
343 | */
|
344 | export declare const Link: LinkComponent
|
345 |
|
346 | /** Redirects to the href as soon as the component is mounted. */
|
347 | export declare const Redirect: (props: React.PropsWithChildren<{ href: Href }>) => ReactNode
|
348 | export type Redirect = typeof Redirect
|
349 |
|
350 | /**
|
351 | * Hooks
|
352 | */
|
353 |
|
354 | export declare function useRouter(): Router
|
355 | type useRouter = typeof useRouter
|
356 |
|
357 | /**
|
358 | * Returns the URL search parameters for the contextually focused route. e.g. \`/acme?foo=bar\` -> \`{ foo: "bar" }\`.
|
359 | * This is useful for stacks where you may push a new screen that changes the query parameters.
|
360 | *
|
361 | * To observe updates even when the invoking route is not focused, use \`useActiveParams()\`.
|
362 | * @see \`useActiveParams\`
|
363 | */
|
364 | export declare function useParams<
|
365 | TParams extends AllRoutes | UnknownOutputParams = UnknownOutputParams,
|
366 | >(): TParams extends AllRoutes ? SearchParams<TParams> : TParams
|
367 | type useParams = typeof useParams
|
368 |
|
369 | export declare function useSearchParams<
|
370 | TParams extends AllRoutes | UnknownOutputParams = UnknownOutputParams,
|
371 | >(): TParams extends AllRoutes ? SearchParams<TParams> : TParams
|
372 | type useSearchParams = typeof useSearchParams
|
373 |
|
374 | /**
|
375 | * Get the globally selected query parameters, including dynamic path segments. This function will update even when the route is not focused.
|
376 | * Useful for analytics or other background operations that don't draw to the screen.
|
377 | *
|
378 | * When querying search params in a stack, opt-towards using \`useParams\` as these will only
|
379 | * update when the route is focused.
|
380 | *
|
381 | * @see \`useParams\`
|
382 | */
|
383 | export declare function useActiveParams<
|
384 | T extends AllRoutes | UnknownOutputParams = UnknownOutputParams,
|
385 | >(): T extends AllRoutes ? SearchParams<T> : T
|
386 | type useActiveParams = typeof useActiveParams
|
387 |
|
388 | /**
|
389 | * Get a list of selected file segments for the currently selected route. Segments are not normalized, so they will be the same as the file path. e.g. /[id]?id=normal -> ["[id]"]
|
390 | *
|
391 | * \`useSegments\` can be typed using an abstract.
|
392 | * Consider the following file structure, and strictly typed \`useSegments\` function:
|
393 | *
|
394 | * \`\`\`md
|
395 | * - app
|
396 | * - [user]
|
397 | * - index.js
|
398 | * - followers.js
|
399 | * - settings.js
|
400 | * \`\`\`
|
401 | * This can be strictly typed using the following abstract:
|
402 | *
|
403 | * \`\`\`ts
|
404 | * const [first, second] = useSegments<['settings'] | ['[user]'] | ['[user]', 'followers']>()
|
405 | * \`\`\`
|
406 | */
|
407 | export declare function useSegments<
|
408 | T extends AbsoluteRoute | RouteSegments<AbsoluteRoute> | RelativePathString,
|
409 | >(): T extends AbsoluteRoute ? RouteSegments<T> : T extends string ? string[] : T
|
410 | type useSegments = typeof useSegments
|
411 | }
|
412 |
|
413 | // TEMP
|
414 | export namespace One {
|
415 | export type Route<Path> = OneRouter.Route<Path>
|
416 | }
|
417 |
|
\ | No newline at end of file |