@nu-art/thunderstorm-frontend 0.400.10 → 0.400.13
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/component-modules/mouse-interactivity/types.d.ts +1 -0
- package/components/TS_MouseInteractivity/TS_PopUp/TS_PopUp.js +1 -0
- package/components/TS_Radio/TS_Radio.js +3 -4
- package/components/TS_V2_TextArea/TS_TextAreaV2.d.ts +1 -1
- package/components/TS_V2_TextArea/TS_TextAreaV2.js +4 -4
- package/modules/ModuleFE_BrowserHistory.d.ts +199 -5
- package/modules/ModuleFE_BrowserHistory.js +242 -4
- package/modules/ModuleFE_LocalStorage.js +9 -9
- package/modules/ModuleFE_Thunderstorm.d.ts +2 -0
- package/modules/ModuleFE_Thunderstorm.js +15 -2
- 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
- package/utils/EditableItem.js +1 -1
- package/utils/tools.d.ts +5 -0
- package/utils/tools.js +4 -0
|
@@ -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.13",
|
|
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.13",
|
|
41
|
+
"@nu-art/firebase-frontend": "0.400.13",
|
|
42
|
+
"@nu-art/firebase-shared": "0.400.13",
|
|
43
|
+
"@nu-art/ts-common": "0.400.13",
|
|
44
|
+
"@nu-art/ts-styles": "0.400.13",
|
|
45
45
|
"abort-controller": "^3.0.0",
|
|
46
46
|
"axios": "^1.13.1",
|
|
47
47
|
"body-parser": "^1.19.0",
|
package/utils/EditableItem.js
CHANGED
|
@@ -501,7 +501,7 @@ export class EditableDBItemV3 extends EditableItem {
|
|
|
501
501
|
if (this.hasValidationError())
|
|
502
502
|
return this.setStatus(EditableItemStatus_FailedValidation);
|
|
503
503
|
if (this.saveError)
|
|
504
|
-
return this.setStatus(
|
|
504
|
+
return this.setStatus(EditableItemStatus_ErrorSaving);
|
|
505
505
|
if (this.hasChanges()) {
|
|
506
506
|
return this.setStatus(EditableItemStatus_UnsavedChanges);
|
|
507
507
|
}
|
package/utils/tools.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Browser } from '@nu-art/thunderstorm-shared/consts';
|
|
2
|
+
import { DBProto } from '@nu-art/ts-common';
|
|
2
3
|
import * as React from 'react';
|
|
3
4
|
import { DependencyList, Dispatch, EffectCallback, SetStateAction } from 'react';
|
|
5
|
+
import { ModuleFE_BaseDB } from '../modules/db-api-gen/ModuleFE_BaseDB.js';
|
|
4
6
|
export declare function browserType(): Browser;
|
|
5
7
|
export declare function base64ToBlob(imageAsBase64: string): Promise<Blob>;
|
|
6
8
|
export declare function stringToArrayBuffer(stringToConvert: string): ArrayBuffer;
|
|
@@ -28,4 +30,7 @@ type MouseClickActions = {
|
|
|
28
30
|
};
|
|
29
31
|
export declare const mouseEventHandler: (e: React.MouseEvent | MouseEvent, actions: MouseClickActions) => void | undefined;
|
|
30
32
|
export declare const stringReplacer: (_content: string, _toReplace: string, replacer: (match: string, i: number) => JSX.Element) => React.ReactNode[];
|
|
33
|
+
export type EntityToResolve<P extends DBProto<any> = DBProto<any>> = string | P['dbType'] | undefined;
|
|
34
|
+
export declare const resolveId: (entity: EntityToResolve) => any;
|
|
35
|
+
export declare const resolveEntity: <P extends DBProto<any>>(module: ModuleFE_BaseDB<P>) => (entity: EntityToResolve<P>) => Readonly<P["dbType"]> | undefined;
|
|
31
36
|
export {};
|
package/utils/tools.js
CHANGED
|
@@ -136,3 +136,7 @@ export const stringReplacer = (_content, _toReplace, replacer) => {
|
|
|
136
136
|
i++;
|
|
137
137
|
}
|
|
138
138
|
};
|
|
139
|
+
export const resolveId = (entity) => typeof entity === 'string' ? entity : entity?._id;
|
|
140
|
+
export const resolveEntity = (module) => (entity) => typeof entity === 'string'
|
|
141
|
+
? module.cache.unique(entity)
|
|
142
|
+
: entity;
|