@nu-art/thunderstorm-frontend 0.400.9 → 0.400.12
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/ModuleFE_BrowserHistory.d.ts +199 -5
- package/modules/ModuleFE_BrowserHistory.js +242 -4
- package/modules/ModuleFE_Thunderstorm.js +1 -1
- package/modules/component-loader/entry-component-loading-module.js +2 -2
- package/modules/routing/ModuleFE_Routing.d.ts +154 -0
- package/modules/routing/ModuleFE_Routing.js +157 -3
- package/modules/routing/ModuleFE_RoutingV2.d.ts +91 -1
- package/modules/routing/ModuleFE_RoutingV2.js +193 -1
- package/modules/routing/index.d.ts +0 -1
- package/modules/routing/index.js +0 -1
- package/package.json +6 -6
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createElement as _createElement } from "react";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { BrowserRouter, Navigate, NavLink, Route, Routes } from 'react-router-dom';
|
|
4
|
-
import { BadImplementationException, composeUrl, Module, removeItemFromArray } from '@nu-art/ts-common';
|
|
4
|
+
import { BadImplementationException, composeQueryParams, composeUrl, exists, Module, removeItemFromArray, _keys } from '@nu-art/ts-common';
|
|
5
5
|
import { LocationChangeListener } from './LocationChangeListener.js';
|
|
6
6
|
import { mouseEventHandler, stopPropagation } from '../../utils/tools.js';
|
|
7
7
|
import { AwaitModules } from '../../components/AwaitModules/AwaitModules.js';
|
|
@@ -126,6 +126,159 @@ class ModuleFE_RoutingV2_Class extends Module {
|
|
|
126
126
|
setNavigate(navigate) {
|
|
127
127
|
this.navigate = navigate;
|
|
128
128
|
}
|
|
129
|
+
// ######################## Query Param Methods ########################
|
|
130
|
+
/**
|
|
131
|
+
* Get all query parameters from the current URL (decoded)
|
|
132
|
+
*/
|
|
133
|
+
getQueryParams() {
|
|
134
|
+
const params = this.getEncodedQueryParams();
|
|
135
|
+
_keys(params).forEach(key => {
|
|
136
|
+
const _param = params[key];
|
|
137
|
+
if (!exists(_param))
|
|
138
|
+
return;
|
|
139
|
+
const value = `${params[key]}`;
|
|
140
|
+
params[key] = decodeURIComponent(value);
|
|
141
|
+
});
|
|
142
|
+
return params;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get a single query parameter from the current URL
|
|
146
|
+
* @param key - The query parameter key
|
|
147
|
+
* @returns The decoded value, null if key exists but value is empty, or undefined if key doesn't exist
|
|
148
|
+
*/
|
|
149
|
+
getQueryParameter(key) {
|
|
150
|
+
const queryParams = this.getQueryParams();
|
|
151
|
+
const value = queryParams[key];
|
|
152
|
+
if (value === undefined && Object.keys(queryParams).includes(key))
|
|
153
|
+
return null;
|
|
154
|
+
return value;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Replace all query parameters on the current route
|
|
158
|
+
* @param queryParams - The query parameters to set
|
|
159
|
+
*/
|
|
160
|
+
setQuery(queryParams) {
|
|
161
|
+
const encodedQueryParams = this.encodeUrlParams(queryParams);
|
|
162
|
+
this.updateQueryParams(encodedQueryParams);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Add or update a single query parameter on the current route
|
|
166
|
+
* @param key - The query parameter key
|
|
167
|
+
* @param value - The query parameter value
|
|
168
|
+
*/
|
|
169
|
+
addQueryParam(key, value) {
|
|
170
|
+
const decodedQueryParams = this.getQueryParams();
|
|
171
|
+
decodedQueryParams[key] = value;
|
|
172
|
+
this.updateQueryParams(decodedQueryParams);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Remove a single query parameter from the current route
|
|
176
|
+
* @param key - The query parameter key to remove
|
|
177
|
+
*/
|
|
178
|
+
removeQueryParam(key) {
|
|
179
|
+
const encodedQueryParams = this.getEncodedQueryParams();
|
|
180
|
+
delete encodedQueryParams[key];
|
|
181
|
+
this.updateQueryParams(encodedQueryParams);
|
|
182
|
+
}
|
|
183
|
+
// ######################## URL Utility Methods ########################
|
|
184
|
+
/**
|
|
185
|
+
* Get the current location object (compatible with BrowserHistory.getCurrent())
|
|
186
|
+
* @returns Object with pathname and search properties
|
|
187
|
+
*/
|
|
188
|
+
getCurrent() {
|
|
189
|
+
return {
|
|
190
|
+
pathname: window.location.pathname,
|
|
191
|
+
search: window.location.search,
|
|
192
|
+
hash: window.location.hash,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get the current URL pathname
|
|
197
|
+
* @returns The current pathname
|
|
198
|
+
*/
|
|
199
|
+
getCurrentUrl() {
|
|
200
|
+
return window.location.pathname;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get the window origin
|
|
204
|
+
* @returns The origin (protocol + hostname + port)
|
|
205
|
+
*/
|
|
206
|
+
getOrigin() {
|
|
207
|
+
return window.location.origin;
|
|
208
|
+
}
|
|
209
|
+
// ######################## Navigation Methods ########################
|
|
210
|
+
/**
|
|
211
|
+
* Navigate to a pathname with optional query params (adds to history)
|
|
212
|
+
* @param location - Location descriptor with pathname and optional search
|
|
213
|
+
*/
|
|
214
|
+
push(location) {
|
|
215
|
+
const url = this.composeLocationUrl(location);
|
|
216
|
+
this.navigate(url);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Replace current history entry with new pathname and optional query params
|
|
220
|
+
* @param location - Location descriptor with pathname and optional search
|
|
221
|
+
*/
|
|
222
|
+
replace(location) {
|
|
223
|
+
const url = this.composeLocationUrl(location);
|
|
224
|
+
this.navigate(url, { replace: true });
|
|
225
|
+
}
|
|
226
|
+
// ######################## Private Helper Methods ########################
|
|
227
|
+
getEncodedQueryParams() {
|
|
228
|
+
const queryParams = {};
|
|
229
|
+
let queryAsString = window.location.search;
|
|
230
|
+
if (!queryAsString || queryAsString.length === 0)
|
|
231
|
+
return {};
|
|
232
|
+
while (queryAsString.startsWith('?') || queryAsString.startsWith('/?')) {
|
|
233
|
+
if (queryAsString.startsWith('?'))
|
|
234
|
+
queryAsString = queryAsString.substring(1);
|
|
235
|
+
else if (queryAsString.startsWith('/?'))
|
|
236
|
+
queryAsString = queryAsString.substring(2);
|
|
237
|
+
else
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
const query = queryAsString.split('&');
|
|
241
|
+
return query.map(param => {
|
|
242
|
+
const parts = param.split('=');
|
|
243
|
+
return { key: parts[0], value: parts[1]?.length === 0 ? undefined : parts[1] };
|
|
244
|
+
}).reduce((toRet, param) => {
|
|
245
|
+
toRet[param.key] = param.value;
|
|
246
|
+
return toRet;
|
|
247
|
+
}, queryParams);
|
|
248
|
+
}
|
|
249
|
+
composeQuery(queryParams) {
|
|
250
|
+
const queryAsString = composeQueryParams(queryParams);
|
|
251
|
+
if (queryAsString.length === 0)
|
|
252
|
+
return '';
|
|
253
|
+
return queryAsString;
|
|
254
|
+
}
|
|
255
|
+
encodeUrlParams(queryParams) {
|
|
256
|
+
const encodedQueryParams = { ...queryParams };
|
|
257
|
+
_keys(encodedQueryParams).forEach(key => {
|
|
258
|
+
const value = encodedQueryParams[key];
|
|
259
|
+
if (!value) {
|
|
260
|
+
delete encodedQueryParams[key];
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
encodedQueryParams[key] = encodeURIComponent(value);
|
|
264
|
+
});
|
|
265
|
+
return encodedQueryParams;
|
|
266
|
+
}
|
|
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
|
+
updateQueryParams(encodedQueryParams) {
|
|
273
|
+
const url = this.createLocationDataFromQueryParams(encodedQueryParams);
|
|
274
|
+
this.navigate(url, { replace: true });
|
|
275
|
+
}
|
|
276
|
+
composeLocationUrl(location) {
|
|
277
|
+
const cleanPathname = !location.pathname.endsWith('/') ? location.pathname : location.pathname.substring(0, location.pathname.length - 1);
|
|
278
|
+
const search = location.search || '';
|
|
279
|
+
const hash = location.hash || '';
|
|
280
|
+
return `${cleanPathname}${search}${hash}`;
|
|
281
|
+
}
|
|
129
282
|
}
|
|
130
283
|
export const TS_NavLink = (props) => {
|
|
131
284
|
const { route, children, ignoreClickOnSameRoute, ..._props } = props;
|
|
@@ -141,3 +294,42 @@ export const TS_NavLink = (props) => {
|
|
|
141
294
|
}) }, children);
|
|
142
295
|
};
|
|
143
296
|
export const ModuleFE_RoutingV2 = new ModuleFE_RoutingV2_Class();
|
|
297
|
+
// ######################## Utility Functions ########################
|
|
298
|
+
/**
|
|
299
|
+
* Encode URL query parameters
|
|
300
|
+
* @param queryParams - Query parameters to encode
|
|
301
|
+
* @returns Encoded query parameters
|
|
302
|
+
*/
|
|
303
|
+
export function encodeUrlParams(queryParams) {
|
|
304
|
+
const encodedQueryParams = { ...queryParams };
|
|
305
|
+
_keys(encodedQueryParams).forEach(key => {
|
|
306
|
+
const value = encodedQueryParams[key];
|
|
307
|
+
if (!value) {
|
|
308
|
+
delete encodedQueryParams[key];
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
encodedQueryParams[key] = encodeURIComponent(value);
|
|
312
|
+
});
|
|
313
|
+
return encodedQueryParams;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Compose a query string from query parameters
|
|
317
|
+
* @param queryParams - Query parameters to compose
|
|
318
|
+
* @returns Query string (without leading ?)
|
|
319
|
+
*/
|
|
320
|
+
export function composeQuery(queryParams) {
|
|
321
|
+
const queryAsString = composeQueryParams(queryParams);
|
|
322
|
+
if (queryAsString.length === 0)
|
|
323
|
+
return '';
|
|
324
|
+
return queryAsString;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Compose a full URL with query parameters
|
|
328
|
+
* @param url - Base URL
|
|
329
|
+
* @param queryParams - Optional query parameters
|
|
330
|
+
* @returns Full URL with query string
|
|
331
|
+
*/
|
|
332
|
+
export function composeURL(url, queryParams) {
|
|
333
|
+
const queryAsString = composeQuery(queryParams);
|
|
334
|
+
return `${url}${queryAsString.length > 0 ? `?${queryAsString}` : ''}`;
|
|
335
|
+
}
|
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.400.
|
|
3
|
+
"version": "0.400.12",
|
|
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.400.
|
|
41
|
-
"@nu-art/firebase-frontend": "0.400.
|
|
42
|
-
"@nu-art/firebase-shared": "0.400.
|
|
43
|
-
"@nu-art/ts-common": "0.400.
|
|
44
|
-
"@nu-art/ts-styles": "0.400.
|
|
40
|
+
"@nu-art/thunderstorm-shared": "0.400.12",
|
|
41
|
+
"@nu-art/firebase-frontend": "0.400.12",
|
|
42
|
+
"@nu-art/firebase-shared": "0.400.12",
|
|
43
|
+
"@nu-art/ts-common": "0.400.12",
|
|
44
|
+
"@nu-art/ts-styles": "0.400.12",
|
|
45
45
|
"abort-controller": "^3.0.0",
|
|
46
46
|
"axios": "^1.13.1",
|
|
47
47
|
"body-parser": "^1.19.0",
|