@nu-art/thunderstorm-frontend 0.401.0 → 0.401.2
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/modules/routing/ModuleFE_RoutingV2.d.ts +12 -6
- package/modules/routing/ModuleFE_RoutingV2.js +51 -29
- package/modules/routing/index.d.ts +0 -1
- package/modules/routing/index.js +0 -1
- package/package.json +6 -6
- package/modules/routing/LocationChangeListener.d.ts +0 -6
- package/modules/routing/LocationChangeListener.js +0 -15
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NavLinkProps } from 'react-router-dom';
|
|
2
2
|
import { TS_Route } from './types.js';
|
|
3
3
|
import { Module } from '@nu-art/ts-common';
|
|
4
|
+
import { ThunderDispatcher } from '../../core/thunder-dispatcher.js';
|
|
4
5
|
import { QueryParams, UrlQueryParams } from '@nu-art/thunderstorm-shared';
|
|
6
|
+
export interface OnLocationChanged {
|
|
7
|
+
__onLocationChanged: (path: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare const dispatch_onLocationChanged: ThunderDispatcher<OnLocationChanged, "__onLocationChanged", [path: string], void>;
|
|
5
10
|
declare class ModuleFE_RoutingV2_Class extends Module<{}> {
|
|
6
11
|
private routesMapByKey;
|
|
7
12
|
private routesMapByPath;
|
|
8
|
-
|
|
9
|
-
goToRoute<P extends QueryParams>(route: TS_Route<P>, params?: Partial<P
|
|
13
|
+
constructor();
|
|
14
|
+
goToRoute<P extends QueryParams>(route: TS_Route<P>, params?: Partial<P>, hash?: string): void;
|
|
10
15
|
redirect<P extends QueryParams>(route: TS_Route<P>, params?: Partial<P>): import("react/jsx-runtime").JSX.Element;
|
|
11
16
|
generateRoutes(rootRoute: TS_Route): import("react/jsx-runtime").JSX.Element;
|
|
12
17
|
buildRouteMap(route: TS_Route, _path?: string): void;
|
|
@@ -15,7 +20,6 @@ declare class ModuleFE_RoutingV2_Class extends Module<{}> {
|
|
|
15
20
|
getRouteByKey(routeKey: string): TS_Route | undefined;
|
|
16
21
|
getFullPath(routeKey: string): string;
|
|
17
22
|
getCurrentRouteKey(): TS_Route;
|
|
18
|
-
setNavigate(navigate: NavigateFunction): void;
|
|
19
23
|
/**
|
|
20
24
|
* Get all query parameters from the current URL (decoded)
|
|
21
25
|
*/
|
|
@@ -63,6 +67,10 @@ declare class ModuleFE_RoutingV2_Class extends Module<{}> {
|
|
|
63
67
|
* @returns The origin (protocol + hostname + port)
|
|
64
68
|
*/
|
|
65
69
|
getOrigin(): string;
|
|
70
|
+
/**
|
|
71
|
+
* Convert location descriptor to URL string using composeUrl
|
|
72
|
+
*/
|
|
73
|
+
private locationToUrl;
|
|
66
74
|
/**
|
|
67
75
|
* Navigate to a pathname with optional query params (adds to history)
|
|
68
76
|
* @param location - Location descriptor with pathname and optional search
|
|
@@ -84,9 +92,7 @@ declare class ModuleFE_RoutingV2_Class extends Module<{}> {
|
|
|
84
92
|
private getEncodedQueryParams;
|
|
85
93
|
private composeQuery;
|
|
86
94
|
private encodeUrlParams;
|
|
87
|
-
private createLocationDataFromQueryParams;
|
|
88
95
|
private updateQueryParams;
|
|
89
|
-
private composeLocationUrl;
|
|
90
96
|
}
|
|
91
97
|
export declare const TS_NavLink: (props: {
|
|
92
98
|
route: TS_Route;
|
|
@@ -1,24 +1,38 @@
|
|
|
1
1
|
import { createElement as _createElement } from "react";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// @ts-ignore - unstable_HistoryRouter may not be in types but is available in React Router v6.4+
|
|
3
4
|
import { BrowserRouter, Navigate, NavLink, Route, Routes } from 'react-router-dom';
|
|
4
|
-
import { BadImplementationException, composeQueryParams, composeUrl, exists, Module, removeItemFromArray
|
|
5
|
-
import {
|
|
5
|
+
import { _keys, BadImplementationException, composeQueryParams, composeUrl, exists, Module, removeItemFromArray } from '@nu-art/ts-common';
|
|
6
|
+
import { ThunderDispatcher } from '../../core/thunder-dispatcher.js';
|
|
6
7
|
import { mouseEventHandler, stopPropagation } from '../../utils/tools.js';
|
|
7
8
|
import { AwaitModules } from '../../components/AwaitModules/AwaitModules.js';
|
|
8
9
|
import { AwaitSync } from '../../components/AwaitSync/AwaitSync.js';
|
|
10
|
+
export const dispatch_onLocationChanged = new ThunderDispatcher('__onLocationChanged');
|
|
9
11
|
class ModuleFE_RoutingV2_Class extends Module {
|
|
10
12
|
// ######################## Inner Data ########################
|
|
11
13
|
routesMapByKey = {};
|
|
12
14
|
routesMapByPath = {};
|
|
13
|
-
|
|
15
|
+
constructor() {
|
|
16
|
+
super();
|
|
17
|
+
// Listen to browser navigation events (back/forward buttons, etc.)
|
|
18
|
+
window.addEventListener('popstate', () => {
|
|
19
|
+
dispatch_onLocationChanged.dispatchUI(window.location.pathname);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
14
22
|
// ######################## Public Functions ########################
|
|
15
|
-
goToRoute(route, params) {
|
|
23
|
+
goToRoute(route, params, hash) {
|
|
16
24
|
const fullPath = this.getFullPath(route.key);
|
|
17
25
|
try {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
const queryString = composeQueryParams(params);
|
|
27
|
+
const search = queryString.length > 0 ? `?${queryString}` : '';
|
|
28
|
+
const url = composeUrl(fullPath, params, hash);
|
|
29
|
+
if (url === window.location.href)
|
|
30
|
+
return this.logWarning(`attempting to set same route: ${fullPath}${search}`);
|
|
31
|
+
// Also update window.location to trigger BrowserRouter's popstate listener
|
|
32
|
+
// This ensures React Router detects the navigation change
|
|
33
|
+
window.history.pushState({}, '', url);
|
|
34
|
+
// Manually dispatch popstate event to trigger BrowserRouter update
|
|
35
|
+
window.dispatchEvent(new PopStateEvent('popstate', { state: {} }));
|
|
22
36
|
}
|
|
23
37
|
catch (e) {
|
|
24
38
|
this.logError(`cannot resolve route for route: `, route, e);
|
|
@@ -33,7 +47,9 @@ class ModuleFE_RoutingV2_Class extends Module {
|
|
|
33
47
|
// This needs to be a component in order to be build the routes on rendering after modules are awaited
|
|
34
48
|
this.buildRouteMap(rootRoute);
|
|
35
49
|
const RoutesRenderer = () => _jsx(Routes, { children: this.routeBuilder(rootRoute) });
|
|
36
|
-
|
|
50
|
+
// Use BrowserRouter - unstable_HistoryRouter has compatibility issues
|
|
51
|
+
// We'll use window.location changes to trigger React Router updates
|
|
52
|
+
return _jsx(BrowserRouter, { children: _jsx(RoutesRenderer, {}) });
|
|
37
53
|
}
|
|
38
54
|
buildRouteMap(route, _path = '') {
|
|
39
55
|
const path = `${_path}/`;
|
|
@@ -123,9 +139,6 @@ class ModuleFE_RoutingV2_Class extends Module {
|
|
|
123
139
|
getCurrentRouteKey() {
|
|
124
140
|
return this.routesMapByPath[window.location.pathname];
|
|
125
141
|
}
|
|
126
|
-
setNavigate(navigate) {
|
|
127
|
-
this.navigate = navigate;
|
|
128
|
-
}
|
|
129
142
|
// ######################## Query Param Methods ########################
|
|
130
143
|
/**
|
|
131
144
|
* Get all query parameters from the current URL (decoded)
|
|
@@ -207,21 +220,38 @@ class ModuleFE_RoutingV2_Class extends Module {
|
|
|
207
220
|
return window.location.origin;
|
|
208
221
|
}
|
|
209
222
|
// ######################## Navigation Methods ########################
|
|
223
|
+
/**
|
|
224
|
+
* Convert location descriptor to URL string using composeUrl
|
|
225
|
+
*/
|
|
226
|
+
locationToUrl(location) {
|
|
227
|
+
// Parse search params if provided as string
|
|
228
|
+
const params = {};
|
|
229
|
+
if (location.search) {
|
|
230
|
+
const searchParams = new URLSearchParams(location.search.startsWith('?') ? location.search.substring(1) : location.search);
|
|
231
|
+
searchParams.forEach((value, key) => {
|
|
232
|
+
params[key] = value;
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
const hash = location.hash?.startsWith('#') ? location.hash.substring(1) : location.hash;
|
|
236
|
+
return composeUrl(location.pathname, params, hash);
|
|
237
|
+
}
|
|
210
238
|
/**
|
|
211
239
|
* Navigate to a pathname with optional query params (adds to history)
|
|
212
240
|
* @param location - Location descriptor with pathname and optional search
|
|
213
241
|
*/
|
|
214
242
|
push(location) {
|
|
215
|
-
const url = this.
|
|
216
|
-
|
|
243
|
+
const url = this.locationToUrl(location);
|
|
244
|
+
window.history.pushState({}, '', url);
|
|
245
|
+
window.dispatchEvent(new PopStateEvent('popstate', { state: {} }));
|
|
217
246
|
}
|
|
218
247
|
/**
|
|
219
248
|
* Replace current history entry with new pathname and optional query params
|
|
220
249
|
* @param location - Location descriptor with pathname and optional search
|
|
221
250
|
*/
|
|
222
251
|
replace(location) {
|
|
223
|
-
const url = this.
|
|
224
|
-
|
|
252
|
+
const url = this.locationToUrl(location);
|
|
253
|
+
window.history.replaceState({}, '', url);
|
|
254
|
+
window.dispatchEvent(new PopStateEvent('popstate', { state: {} }));
|
|
225
255
|
}
|
|
226
256
|
// ######################## Private Helper Methods ########################
|
|
227
257
|
getEncodedQueryParams() {
|
|
@@ -264,20 +294,12 @@ class ModuleFE_RoutingV2_Class extends Module {
|
|
|
264
294
|
});
|
|
265
295
|
return encodedQueryParams;
|
|
266
296
|
}
|
|
267
|
-
createLocationDataFromQueryParams(encodedQueryParams, pathname = window.location.pathname) {
|
|
268
|
-
const cleanPathname = !pathname.endsWith('/') ? pathname : pathname.substring(0, pathname.length - 1);
|
|
269
|
-
const search = encodedQueryParams ? this.composeQuery(encodedQueryParams) : '';
|
|
270
|
-
return search.length > 0 ? `${cleanPathname}?${search}` : cleanPathname;
|
|
271
|
-
}
|
|
272
297
|
updateQueryParams(encodedQueryParams) {
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const search = location.search || '';
|
|
279
|
-
const hash = location.hash || '';
|
|
280
|
-
return `${cleanPathname}${search}${hash}`;
|
|
298
|
+
const search = this.composeQuery(encodedQueryParams);
|
|
299
|
+
const url = `${window.location.pathname}${search ? `?${search}` : ''}`;
|
|
300
|
+
window.history.replaceState({}, '', url);
|
|
301
|
+
// Manually dispatch popstate event to trigger BrowserRouter update
|
|
302
|
+
window.dispatchEvent(new PopStateEvent('popstate', { state: {} }));
|
|
281
303
|
}
|
|
282
304
|
}
|
|
283
305
|
export const TS_NavLink = (props) => {
|
package/modules/routing/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nu-art/thunderstorm-frontend",
|
|
3
|
-
"version": "0.401.
|
|
3
|
+
"version": "0.401.2",
|
|
4
4
|
"description": "Thunderstorm Frontend",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"TacB0sS",
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
"linkDirectory": true
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@nu-art/thunderstorm-shared": "0.401.
|
|
41
|
-
"@nu-art/firebase-frontend": "0.401.
|
|
42
|
-
"@nu-art/firebase-shared": "0.401.
|
|
43
|
-
"@nu-art/ts-common": "0.401.
|
|
44
|
-
"@nu-art/ts-styles": "0.401.
|
|
40
|
+
"@nu-art/thunderstorm-shared": "0.401.2",
|
|
41
|
+
"@nu-art/firebase-frontend": "0.401.2",
|
|
42
|
+
"@nu-art/firebase-shared": "0.401.2",
|
|
43
|
+
"@nu-art/ts-common": "0.401.2",
|
|
44
|
+
"@nu-art/ts-styles": "0.401.2",
|
|
45
45
|
"abort-controller": "^3.0.0",
|
|
46
46
|
"axios": "^1.13.1",
|
|
47
47
|
"body-parser": "^1.19.0",
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { ThunderDispatcher } from '../../core/thunder-dispatcher.js';
|
|
2
|
-
export interface OnLocationChanged {
|
|
3
|
-
__onLocationChanged: (path: string) => void;
|
|
4
|
-
}
|
|
5
|
-
export declare const dispatch_onLocationChanged: ThunderDispatcher<OnLocationChanged, "__onLocationChanged", [path: string], void>;
|
|
6
|
-
export declare const LocationChangeListener: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useLocation, useNavigate } from 'react-router-dom';
|
|
3
|
-
import { useEffect } from 'react';
|
|
4
|
-
import { ThunderDispatcher } from '../../core/thunder-dispatcher.js';
|
|
5
|
-
import { ModuleFE_RoutingV2 } from './ModuleFE_RoutingV2.js';
|
|
6
|
-
export const dispatch_onLocationChanged = new ThunderDispatcher('__onLocationChanged');
|
|
7
|
-
export const LocationChangeListener = () => {
|
|
8
|
-
const location = useLocation();
|
|
9
|
-
const navigate = useNavigate();
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
dispatch_onLocationChanged.dispatchUI(location.pathname);
|
|
12
|
-
}, [location]);
|
|
13
|
-
ModuleFE_RoutingV2.setNavigate(navigate);
|
|
14
|
-
return _jsx(_Fragment, {});
|
|
15
|
-
};
|