@openwebf/react-router 0.3.2 → 0.3.4
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.
- package/dist/browser/index.d.ts +88 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/index.d.ts +77 -3
- package/dist/index.esm.js +160 -51
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +163 -50
- package/dist/index.js.map +1 -1
- package/dist/routes/Route.d.ts +8 -1
- package/dist/routes/Route.d.ts.map +1 -1
- package/dist/routes/Routes.d.ts +30 -0
- package/dist/routes/Routes.d.ts.map +1 -1
- package/dist/routes/utils.d.ts +37 -0
- package/dist/routes/utils.d.ts.map +1 -1
- package/dist/utils/RouterLink.d.ts +1 -0
- package/dist/utils/RouterLink.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/routes/router.d.ts +0 -79
- package/dist/routes/router.d.ts.map +0 -1
- package/dist/routes/routerConfig.d.ts +0 -147
- package/dist/routes/routerConfig.d.ts.map +0 -1
- package/dist/utils/CreateComponent.d.ts +0 -86
- package/dist/utils/CreateComponent.d.ts.map +0 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface RouteProps {
|
|
3
|
+
title?: string;
|
|
4
|
+
path: string;
|
|
5
|
+
prerender?: boolean;
|
|
6
|
+
element: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export interface RoutesProps {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export interface Location {
|
|
12
|
+
pathname: string;
|
|
13
|
+
state: any;
|
|
14
|
+
key?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface RouteParams {
|
|
17
|
+
[key: string]: string;
|
|
18
|
+
}
|
|
19
|
+
export interface RouteMatch {
|
|
20
|
+
path: string;
|
|
21
|
+
params: RouteParams;
|
|
22
|
+
isExact: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface RouteContext<S = any> {
|
|
25
|
+
path: string | undefined;
|
|
26
|
+
params: S | undefined;
|
|
27
|
+
routeParams: RouteParams | undefined;
|
|
28
|
+
activePath: string | undefined;
|
|
29
|
+
routeEventKind?: 'didPushNext' | 'didPush' | 'didPop' | 'didPopNext';
|
|
30
|
+
}
|
|
31
|
+
export interface NavigateOptions {
|
|
32
|
+
replace?: boolean;
|
|
33
|
+
state?: any;
|
|
34
|
+
}
|
|
35
|
+
export interface NavigateFunction {
|
|
36
|
+
(to: string, options?: NavigateOptions): void;
|
|
37
|
+
(delta: number): void;
|
|
38
|
+
}
|
|
39
|
+
export interface NavigationMethods {
|
|
40
|
+
navigate: NavigateFunction;
|
|
41
|
+
pop: (result?: any) => void;
|
|
42
|
+
popUntil: (path: string) => void;
|
|
43
|
+
popAndPush: (path: string, state?: any) => Promise<void>;
|
|
44
|
+
pushAndRemoveUntil: (newPath: string, untilPath: string, state?: any) => Promise<void>;
|
|
45
|
+
canPop: () => boolean;
|
|
46
|
+
maybePop: (result?: any) => boolean;
|
|
47
|
+
}
|
|
48
|
+
export declare function Route({ path, element }: RouteProps): React.JSX.Element;
|
|
49
|
+
export declare function Routes({ children }: RoutesProps): React.JSX.Element;
|
|
50
|
+
export declare function useLocation(): Location & {
|
|
51
|
+
isActive: boolean;
|
|
52
|
+
};
|
|
53
|
+
export declare function useRouteContext(): RouteContext & {
|
|
54
|
+
isActive: boolean;
|
|
55
|
+
};
|
|
56
|
+
export declare function useParams(): RouteParams;
|
|
57
|
+
export declare function useRoutes(routes: Array<{
|
|
58
|
+
path: string;
|
|
59
|
+
element: React.ReactNode;
|
|
60
|
+
prerender?: boolean;
|
|
61
|
+
children?: any[];
|
|
62
|
+
}>): React.ReactElement | null;
|
|
63
|
+
export declare function useNavigate(): NavigationMethods;
|
|
64
|
+
export declare function pathToRegex(pattern: string): {
|
|
65
|
+
regex: RegExp;
|
|
66
|
+
paramNames: string[];
|
|
67
|
+
};
|
|
68
|
+
export declare function matchPath(pattern: string, pathname: string): RouteMatch | null;
|
|
69
|
+
export declare function matchRoutes(routes: string[], pathname: string): RouteMatch | null;
|
|
70
|
+
export declare const WebFRouter: {
|
|
71
|
+
readonly state: any;
|
|
72
|
+
readonly path: string;
|
|
73
|
+
push: (path: string, state?: any) => Promise<void>;
|
|
74
|
+
replace: (path: string, state?: any) => Promise<void>;
|
|
75
|
+
back: () => void;
|
|
76
|
+
pop: (result?: any) => void;
|
|
77
|
+
popUntil: (path: string) => void;
|
|
78
|
+
popAndPushNamed: (path: string, state?: any) => Promise<void>;
|
|
79
|
+
pushNamedAndRemoveUntil: (path: string, _state: any, _untilPath: string) => Promise<void>;
|
|
80
|
+
pushNamedAndRemoveUntilRoute: (newPath: string, _untilPath: string, state?: any) => Promise<void>;
|
|
81
|
+
canPop: () => boolean;
|
|
82
|
+
maybePop: (result?: any) => boolean;
|
|
83
|
+
pushState: (state: any, name: string) => void;
|
|
84
|
+
replaceState: (state: any, name: string) => void;
|
|
85
|
+
restorablePopAndPushState: (state: any, _name: string) => string;
|
|
86
|
+
restorablePopAndPushNamed: (path: string, state?: any) => Promise<string>;
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -78,6 +78,43 @@ declare const WebFRouter: {
|
|
|
78
78
|
*/
|
|
79
79
|
restorablePopAndPushNamed: <T extends RoutePath>(path: T, state?: any) => Promise<string>;
|
|
80
80
|
};
|
|
81
|
+
/**
|
|
82
|
+
* Route parameters extracted from dynamic routes
|
|
83
|
+
*/
|
|
84
|
+
interface RouteParams {
|
|
85
|
+
[key: string]: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Route match result
|
|
89
|
+
*/
|
|
90
|
+
interface RouteMatch {
|
|
91
|
+
path: string;
|
|
92
|
+
params: RouteParams;
|
|
93
|
+
isExact: boolean;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Convert a route pattern to a regular expression
|
|
97
|
+
* @param pattern Route pattern like "/user/:userId" or "/category/:catId/product/:prodId"
|
|
98
|
+
* @returns Object with regex and parameter names
|
|
99
|
+
*/
|
|
100
|
+
declare function pathToRegex(pattern: string): {
|
|
101
|
+
regex: RegExp;
|
|
102
|
+
paramNames: string[];
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Match a pathname against a route pattern and extract parameters
|
|
106
|
+
* @param pattern Route pattern like "/user/:userId"
|
|
107
|
+
* @param pathname Actual pathname like "/user/123"
|
|
108
|
+
* @returns Match result with extracted parameters or null if no match
|
|
109
|
+
*/
|
|
110
|
+
declare function matchPath(pattern: string, pathname: string): RouteMatch | null;
|
|
111
|
+
/**
|
|
112
|
+
* Find the best matching route from a list of route patterns
|
|
113
|
+
* @param routes Array of route patterns
|
|
114
|
+
* @param pathname Current pathname
|
|
115
|
+
* @returns Best match or null if no routes match
|
|
116
|
+
*/
|
|
117
|
+
declare function matchRoutes(routes: string[], pathname: string): RouteMatch | null;
|
|
81
118
|
|
|
82
119
|
/**
|
|
83
120
|
* Route Component
|
|
@@ -116,13 +153,20 @@ interface RouteProps {
|
|
|
116
153
|
* The actual page component to render
|
|
117
154
|
*/
|
|
118
155
|
element: React.ReactNode;
|
|
156
|
+
/**
|
|
157
|
+
* Theme for this route
|
|
158
|
+
* Controls the visual style of the navigation bar and page
|
|
159
|
+
*
|
|
160
|
+
* @default "material"
|
|
161
|
+
*/
|
|
162
|
+
theme?: 'material' | 'cupertino';
|
|
119
163
|
}
|
|
120
164
|
/**
|
|
121
165
|
* Route Component
|
|
122
166
|
*
|
|
123
167
|
* Responsible for managing page rendering, lifecycle and navigation bar
|
|
124
168
|
*/
|
|
125
|
-
declare function Route({ path, prerender, element, title }: RouteProps): React.JSX.Element;
|
|
169
|
+
declare function Route({ path, prerender, element, title, theme }: RouteProps): React.JSX.Element;
|
|
126
170
|
|
|
127
171
|
/**
|
|
128
172
|
* Hook to get route context
|
|
@@ -149,6 +193,10 @@ declare function useRouteContext(): {
|
|
|
149
193
|
* State data passed during route navigation
|
|
150
194
|
*/
|
|
151
195
|
params: any;
|
|
196
|
+
/**
|
|
197
|
+
* Route parameters extracted from dynamic routes (e.g., :userId in /user/:userId)
|
|
198
|
+
*/
|
|
199
|
+
routeParams: RouteParams | undefined;
|
|
152
200
|
/**
|
|
153
201
|
* Current active path from router
|
|
154
202
|
*/
|
|
@@ -186,6 +234,7 @@ interface Location {
|
|
|
186
234
|
* const location = useLocation();
|
|
187
235
|
*
|
|
188
236
|
* console.log('Current path:', location.pathname);
|
|
237
|
+
|
|
189
238
|
* console.log('Location state:', location.state);
|
|
190
239
|
* console.log('Is active:', location.isActive);
|
|
191
240
|
*
|
|
@@ -196,6 +245,24 @@ interface Location {
|
|
|
196
245
|
declare function useLocation(): Location & {
|
|
197
246
|
isActive: boolean;
|
|
198
247
|
};
|
|
248
|
+
/**
|
|
249
|
+
* Hook to get route parameters from dynamic routes
|
|
250
|
+
*
|
|
251
|
+
* @returns Route parameters object with parameter names as keys and values as strings
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```tsx
|
|
255
|
+
* // For route pattern "/user/:userId" and actual path "/user/123"
|
|
256
|
+
* function UserPage() {
|
|
257
|
+
* const params = useParams();
|
|
258
|
+
*
|
|
259
|
+
* console.log(params.userId); // "123"
|
|
260
|
+
*
|
|
261
|
+
* return <div>User ID: {params.userId}</div>;
|
|
262
|
+
* }
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
declare function useParams(): RouteParams;
|
|
199
266
|
/**
|
|
200
267
|
* Route configuration object
|
|
201
268
|
*/
|
|
@@ -212,6 +279,12 @@ interface RouteObject {
|
|
|
212
279
|
* Whether to pre-render this route
|
|
213
280
|
*/
|
|
214
281
|
prerender?: boolean;
|
|
282
|
+
/**
|
|
283
|
+
* Theme for this route
|
|
284
|
+
*
|
|
285
|
+
* @default "material"
|
|
286
|
+
*/
|
|
287
|
+
theme?: 'material' | 'cupertino';
|
|
215
288
|
/**
|
|
216
289
|
* Child routes (not supported yet)
|
|
217
290
|
*/
|
|
@@ -337,6 +410,7 @@ type HybridRouterChangeEventHandler = EventHandler<HybridRouterChangeEvent>;
|
|
|
337
410
|
interface WebFHybridRouterProps {
|
|
338
411
|
path: string;
|
|
339
412
|
title?: string;
|
|
413
|
+
theme?: 'material' | 'cupertino';
|
|
340
414
|
onScreen?: HybridRouterChangeEventHandler;
|
|
341
415
|
offScreen?: HybridRouterChangeEventHandler;
|
|
342
416
|
children?: ReactNode;
|
|
@@ -345,5 +419,5 @@ interface WebFRouterLinkElement extends WebFElementWithMethods<{}> {
|
|
|
345
419
|
}
|
|
346
420
|
declare const WebFRouterLink: FC<WebFHybridRouterProps>;
|
|
347
421
|
|
|
348
|
-
export { Route, Routes, WebFRouter, WebFRouterLink, useLocation, useNavigate, useRouteContext, useRoutes };
|
|
349
|
-
export type { HybridRouterChangeEvent, HybridRouterChangeEventHandler, Location, NavigateFunction, NavigateOptions, NavigationMethods, RouteObject, RouteProps, RoutesProps, WebFHybridRouterProps, WebFRouterLinkElement };
|
|
422
|
+
export { Route, Routes, WebFRouter, WebFRouterLink, matchPath, matchRoutes, pathToRegex, useLocation, useNavigate, useParams, useRouteContext, useRoutes };
|
|
423
|
+
export type { HybridRouterChangeEvent, HybridRouterChangeEventHandler, Location, NavigateFunction, NavigateOptions, NavigationMethods, RouteMatch, RouteObject, RouteParams, RouteProps, RoutesProps, WebFHybridRouterProps, WebFRouterLinkElement };
|
package/dist/index.esm.js
CHANGED
|
@@ -142,44 +142,101 @@ const WebFRouter = {
|
|
|
142
142
|
return webf.hybridHistory.restorablePopAndPushNamed(path, { arguments: state });
|
|
143
143
|
})
|
|
144
144
|
};
|
|
145
|
+
/**
|
|
146
|
+
* Convert a route pattern to a regular expression
|
|
147
|
+
* @param pattern Route pattern like "/user/:userId" or "/category/:catId/product/:prodId"
|
|
148
|
+
* @returns Object with regex and parameter names
|
|
149
|
+
*/
|
|
150
|
+
function pathToRegex(pattern) {
|
|
151
|
+
const paramNames = [];
|
|
152
|
+
// Escape special regex characters except : and *
|
|
153
|
+
let regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
154
|
+
// Replace :param with named capture groups
|
|
155
|
+
regexPattern = regexPattern.replace(/:([^\/]+)/g, (_, paramName) => {
|
|
156
|
+
paramNames.push(paramName);
|
|
157
|
+
return '([^/]+)';
|
|
158
|
+
});
|
|
159
|
+
// Add anchors for exact matching
|
|
160
|
+
regexPattern = `^${regexPattern}$`;
|
|
161
|
+
return {
|
|
162
|
+
regex: new RegExp(regexPattern),
|
|
163
|
+
paramNames
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Match a pathname against a route pattern and extract parameters
|
|
168
|
+
* @param pattern Route pattern like "/user/:userId"
|
|
169
|
+
* @param pathname Actual pathname like "/user/123"
|
|
170
|
+
* @returns Match result with extracted parameters or null if no match
|
|
171
|
+
*/
|
|
172
|
+
function matchPath(pattern, pathname) {
|
|
173
|
+
const { regex, paramNames } = pathToRegex(pattern);
|
|
174
|
+
const match = pathname.match(regex);
|
|
175
|
+
if (!match) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
// Extract parameters from capture groups
|
|
179
|
+
const params = {};
|
|
180
|
+
paramNames.forEach((paramName, index) => {
|
|
181
|
+
params[paramName] = match[index + 1]; // +1 because match[0] is the full match
|
|
182
|
+
});
|
|
183
|
+
return {
|
|
184
|
+
path: pattern,
|
|
185
|
+
params,
|
|
186
|
+
isExact: true
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Find the best matching route from a list of route patterns
|
|
191
|
+
* @param routes Array of route patterns
|
|
192
|
+
* @param pathname Current pathname
|
|
193
|
+
* @returns Best match or null if no routes match
|
|
194
|
+
*/
|
|
195
|
+
function matchRoutes(routes, pathname) {
|
|
196
|
+
for (const route of routes) {
|
|
197
|
+
const match = matchPath(route, pathname);
|
|
198
|
+
if (match) {
|
|
199
|
+
return match;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
145
204
|
|
|
146
205
|
var isFunction = function (value) {
|
|
147
|
-
|
|
206
|
+
return typeof value === 'function';
|
|
148
207
|
};
|
|
149
208
|
|
|
150
209
|
var isDev = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
|
|
151
210
|
|
|
152
|
-
function
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
211
|
+
var useMemoizedFn = function (fn) {
|
|
212
|
+
if (isDev) {
|
|
213
|
+
if (!isFunction(fn)) {
|
|
214
|
+
console.error("useMemoizedFn expected parameter is a function, got ".concat(typeof fn));
|
|
215
|
+
}
|
|
156
216
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
return memoizedFn.current;
|
|
175
|
-
}
|
|
217
|
+
var fnRef = useRef(fn);
|
|
218
|
+
// why not write `fnRef.current = fn`?
|
|
219
|
+
// https://github.com/alibaba/hooks/issues/728
|
|
220
|
+
fnRef.current = useMemo(function () { return fn; }, [fn]);
|
|
221
|
+
var memoizedFn = useRef(undefined);
|
|
222
|
+
if (!memoizedFn.current) {
|
|
223
|
+
memoizedFn.current = function () {
|
|
224
|
+
var args = [];
|
|
225
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
226
|
+
args[_i] = arguments[_i];
|
|
227
|
+
}
|
|
228
|
+
return fnRef.current.apply(this, args);
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
return memoizedFn.current;
|
|
232
|
+
};
|
|
176
233
|
|
|
177
234
|
// Create the raw component using createWebFComponent
|
|
178
235
|
const RawWebFRouterLink = createWebFComponent({
|
|
179
236
|
tagName: 'webf-router-link',
|
|
180
237
|
displayName: 'WebFRouterLink',
|
|
181
238
|
// Map props to attributes
|
|
182
|
-
attributeProps: ['path', 'title'],
|
|
239
|
+
attributeProps: ['path', 'title', 'theme'],
|
|
183
240
|
// Event handlers
|
|
184
241
|
events: [
|
|
185
242
|
{
|
|
@@ -208,7 +265,7 @@ const WebFRouterLink = function (props) {
|
|
|
208
265
|
props.onScreen(event);
|
|
209
266
|
}
|
|
210
267
|
};
|
|
211
|
-
return (React.createElement(RawWebFRouterLink, { title: props.title, path: props.path, onScreen: handleOnScreen, offScreen: props.offScreen }, isRender ? props.children : null));
|
|
268
|
+
return (React.createElement(RawWebFRouterLink, { title: props.title, path: props.path, theme: props.theme, onScreen: handleOnScreen, offScreen: props.offScreen }, isRender ? props.children : null));
|
|
212
269
|
};
|
|
213
270
|
|
|
214
271
|
/**
|
|
@@ -225,7 +282,7 @@ const WebFRouterLink = function (props) {
|
|
|
225
282
|
*
|
|
226
283
|
* Responsible for managing page rendering, lifecycle and navigation bar
|
|
227
284
|
*/
|
|
228
|
-
function Route({ path, prerender = false, element, title }) {
|
|
285
|
+
function Route({ path, prerender = false, element, title, theme = 'material' }) {
|
|
229
286
|
// Mark whether the page has been rendered
|
|
230
287
|
const [hasRendered, updateRender] = useState(false);
|
|
231
288
|
/**
|
|
@@ -244,7 +301,7 @@ function Route({ path, prerender = false, element, title }) {
|
|
|
244
301
|
*/
|
|
245
302
|
const handleOffScreen = useMemoizedFn(() => {
|
|
246
303
|
});
|
|
247
|
-
return (React.createElement(WebFRouterLink, { path: path, title: title, onScreen: handleOnScreen, offScreen: handleOffScreen }, shouldRenderChildren ? element : null));
|
|
304
|
+
return (React.createElement(WebFRouterLink, { path: path, title: title, theme: theme, onScreen: handleOnScreen, offScreen: handleOffScreen }, shouldRenderChildren ? element : null));
|
|
248
305
|
}
|
|
249
306
|
|
|
250
307
|
/**
|
|
@@ -253,6 +310,7 @@ function Route({ path, prerender = false, element, title }) {
|
|
|
253
310
|
const RouteContext = createContext({
|
|
254
311
|
path: undefined,
|
|
255
312
|
params: undefined,
|
|
313
|
+
routeParams: undefined,
|
|
256
314
|
activePath: undefined,
|
|
257
315
|
routeEventKind: undefined
|
|
258
316
|
});
|
|
@@ -287,6 +345,7 @@ function useRouteContext() {
|
|
|
287
345
|
* const location = useLocation();
|
|
288
346
|
*
|
|
289
347
|
* console.log('Current path:', location.pathname);
|
|
348
|
+
|
|
290
349
|
* console.log('Location state:', location.state);
|
|
291
350
|
* console.log('Is active:', location.isActive);
|
|
292
351
|
*
|
|
@@ -298,25 +357,46 @@ function useLocation() {
|
|
|
298
357
|
const context = useRouteContext();
|
|
299
358
|
// Create location object from context
|
|
300
359
|
const location = useMemo(() => {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
// For inactive routes, return the global location without state
|
|
360
|
+
const currentPath = context.path || context.activePath || WebFRouter.path;
|
|
361
|
+
let pathname = currentPath;
|
|
362
|
+
// Check if the current component's route matches the active path
|
|
363
|
+
const isCurrentRoute = context.path === context.activePath;
|
|
364
|
+
// Get state - prioritize context params, fallback to WebFRouter.state
|
|
365
|
+
const state = (context.isActive || isCurrentRoute)
|
|
366
|
+
? (context.params || WebFRouter.state)
|
|
367
|
+
: WebFRouter.state;
|
|
311
368
|
return {
|
|
312
|
-
pathname
|
|
313
|
-
state
|
|
314
|
-
isActive:
|
|
315
|
-
key: `${
|
|
369
|
+
pathname,
|
|
370
|
+
state,
|
|
371
|
+
isActive: context.isActive,
|
|
372
|
+
key: `${pathname}-${Date.now()}`
|
|
316
373
|
};
|
|
317
374
|
}, [context.isActive, context.path, context.activePath, context.params]);
|
|
318
375
|
return location;
|
|
319
376
|
}
|
|
377
|
+
/**
|
|
378
|
+
* Hook to get route parameters from dynamic routes
|
|
379
|
+
*
|
|
380
|
+
* @returns Route parameters object with parameter names as keys and values as strings
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* ```tsx
|
|
384
|
+
* // For route pattern "/user/:userId" and actual path "/user/123"
|
|
385
|
+
* function UserPage() {
|
|
386
|
+
* const params = useParams();
|
|
387
|
+
*
|
|
388
|
+
* console.log(params.userId); // "123"
|
|
389
|
+
*
|
|
390
|
+
* return <div>User ID: {params.userId}</div>;
|
|
391
|
+
* }
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
function useParams() {
|
|
395
|
+
const context = useRouteContext();
|
|
396
|
+
return useMemo(() => {
|
|
397
|
+
return context.routeParams || {};
|
|
398
|
+
}, [context.routeParams]);
|
|
399
|
+
}
|
|
320
400
|
/**
|
|
321
401
|
* Routes component that wraps multiple Route components and provides shared context
|
|
322
402
|
*
|
|
@@ -336,11 +416,17 @@ function RouteContextProvider({ path, children }) {
|
|
|
336
416
|
const globalContext = useContext(RouteContext);
|
|
337
417
|
// Create a route-specific context that only updates when this route is active
|
|
338
418
|
const routeSpecificContext = useMemo(() => {
|
|
339
|
-
//
|
|
340
|
-
|
|
419
|
+
// Check if this route pattern matches the active path
|
|
420
|
+
const match = globalContext.activePath ? matchPath(path, globalContext.activePath) : null;
|
|
421
|
+
if (match) {
|
|
422
|
+
// Use route params from Flutter event if available, otherwise from local matching
|
|
423
|
+
const effectiveRouteParams = globalContext.routeParams || match.params;
|
|
424
|
+
// For matching routes, always try to get state from WebFRouter if params is undefined
|
|
425
|
+
const effectiveParams = globalContext.params !== undefined ? globalContext.params : WebFRouter.state;
|
|
341
426
|
return {
|
|
342
427
|
path,
|
|
343
|
-
params:
|
|
428
|
+
params: effectiveParams,
|
|
429
|
+
routeParams: effectiveRouteParams,
|
|
344
430
|
activePath: globalContext.activePath,
|
|
345
431
|
routeEventKind: globalContext.routeEventKind
|
|
346
432
|
};
|
|
@@ -349,33 +435,55 @@ function RouteContextProvider({ path, children }) {
|
|
|
349
435
|
return {
|
|
350
436
|
path,
|
|
351
437
|
params: undefined,
|
|
438
|
+
routeParams: undefined,
|
|
352
439
|
activePath: globalContext.activePath,
|
|
353
440
|
routeEventKind: undefined
|
|
354
441
|
};
|
|
355
|
-
}, [path, globalContext.activePath, globalContext.params, globalContext.routeEventKind]);
|
|
442
|
+
}, [path, globalContext.activePath, globalContext.params, globalContext.routeParams, globalContext.routeEventKind]);
|
|
356
443
|
return (React.createElement(RouteContext.Provider, { value: routeSpecificContext }, children));
|
|
357
444
|
}
|
|
358
445
|
function Routes({ children }) {
|
|
359
446
|
// State to track current route information
|
|
360
447
|
const [routeState, setRouteState] = useState({
|
|
361
448
|
path: undefined,
|
|
362
|
-
activePath:
|
|
449
|
+
activePath: WebFRouter.path, // Initialize with current path
|
|
363
450
|
params: undefined,
|
|
451
|
+
routeParams: undefined,
|
|
364
452
|
routeEventKind: undefined
|
|
365
453
|
});
|
|
366
454
|
// Listen to hybridrouterchange event
|
|
367
455
|
useEffect(() => {
|
|
368
456
|
const handleRouteChange = (event) => {
|
|
369
457
|
const routeEvent = event;
|
|
458
|
+
// Check for new event detail structure with params
|
|
459
|
+
const eventDetail = event.detail;
|
|
370
460
|
// Only update activePath for push events
|
|
371
461
|
const newActivePath = (routeEvent.kind === 'didPushNext' || routeEvent.kind === 'didPush')
|
|
372
462
|
? routeEvent.path
|
|
373
463
|
: routeState.activePath;
|
|
464
|
+
// For dynamic routes, extract parameters from the path using registered route patterns
|
|
465
|
+
let routeParams = (eventDetail === null || eventDetail === void 0 ? void 0 : eventDetail.params) || undefined;
|
|
466
|
+
if (!routeParams && newActivePath) {
|
|
467
|
+
// Try to extract parameters from registered route patterns
|
|
468
|
+
const registeredRoutes = Array.from(document.querySelectorAll('webf-router-link'));
|
|
469
|
+
for (const routeElement of registeredRoutes) {
|
|
470
|
+
const routePath = routeElement.getAttribute('path');
|
|
471
|
+
if (routePath && routePath.includes(':')) {
|
|
472
|
+
const match = matchPath(routePath, newActivePath);
|
|
473
|
+
if (match) {
|
|
474
|
+
routeParams = match.params;
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
const eventState = (eventDetail === null || eventDetail === void 0 ? void 0 : eventDetail.state) || routeEvent.state;
|
|
374
481
|
// Update state based on event kind
|
|
375
482
|
setRouteState({
|
|
376
483
|
path: routeEvent.path,
|
|
377
484
|
activePath: newActivePath,
|
|
378
|
-
params:
|
|
485
|
+
params: eventState,
|
|
486
|
+
routeParams: routeParams, // Use params from Flutter if available
|
|
379
487
|
routeEventKind: routeEvent.kind
|
|
380
488
|
});
|
|
381
489
|
};
|
|
@@ -390,9 +498,10 @@ function Routes({ children }) {
|
|
|
390
498
|
const globalContextValue = useMemo(() => ({
|
|
391
499
|
path: undefined,
|
|
392
500
|
params: routeState.params,
|
|
501
|
+
routeParams: routeState.routeParams, // Pass through route params from Flutter
|
|
393
502
|
activePath: routeState.activePath,
|
|
394
503
|
routeEventKind: routeState.routeEventKind
|
|
395
|
-
}), [routeState.activePath, routeState.params, routeState.routeEventKind]);
|
|
504
|
+
}), [routeState.activePath, routeState.params, routeState.routeParams, routeState.routeEventKind]);
|
|
396
505
|
// Wrap each Route component with its own context provider
|
|
397
506
|
const wrappedChildren = useMemo(() => {
|
|
398
507
|
return Children.map(children, (child) => {
|
|
@@ -438,7 +547,7 @@ function useRoutes(routes) {
|
|
|
438
547
|
if (route.children && route.children.length > 0) {
|
|
439
548
|
console.warn('Nested routes are not supported yet');
|
|
440
549
|
}
|
|
441
|
-
return (React.createElement(Route, { key: route.path, path: route.path, element: route.element, prerender: route.prerender }));
|
|
550
|
+
return (React.createElement(Route, { key: route.path, path: route.path, element: route.element, prerender: route.prerender, theme: route.theme }));
|
|
442
551
|
});
|
|
443
552
|
}, [routes]);
|
|
444
553
|
// Return Routes component with Route children
|
|
@@ -508,5 +617,5 @@ function useNavigate() {
|
|
|
508
617
|
}, []);
|
|
509
618
|
}
|
|
510
619
|
|
|
511
|
-
export { Route, Routes, WebFRouter, WebFRouterLink, useLocation, useNavigate, useRouteContext, useRoutes };
|
|
620
|
+
export { Route, Routes, WebFRouter, WebFRouterLink, matchPath, matchRoutes, pathToRegex, useLocation, useNavigate, useParams, useRouteContext, useRoutes };
|
|
512
621
|
//# sourceMappingURL=index.esm.js.map
|