@openwebf/react-router 0.24.2 → 1.0.0
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/index.d.ts +40 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +525 -67
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +528 -65
- package/dist/index.js.map +1 -1
- package/dist/platform/browserHistory.d.ts +114 -0
- package/dist/platform/browserHistory.d.ts.map +1 -0
- package/dist/platform/index.d.ts +32 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/routes/utils.d.ts +2 -1
- package/dist/routes/utils.d.ts.map +1 -1
- package/dist/utils/RouterLink.d.ts +4 -2
- package/dist/utils/RouterLink.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import React, { useRef, useMemo, useState, createContext, useContext,
|
|
2
|
-
import { createWebFComponent } from '@openwebf/react-core-ui';
|
|
1
|
+
import React, { useRef, useMemo, useState, useEffect, createContext, useContext, Children, isValidElement } from 'react';
|
|
3
2
|
|
|
4
3
|
/******************************************************************************
|
|
5
4
|
Copyright (c) Microsoft Corporation.
|
|
@@ -34,14 +33,347 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
34
33
|
};
|
|
35
34
|
|
|
36
35
|
/**
|
|
37
|
-
*
|
|
36
|
+
* Platform detection and abstraction layer
|
|
38
37
|
*
|
|
39
|
-
*
|
|
38
|
+
* Detects whether running in WebF or standard browser environment
|
|
39
|
+
* and provides a unified interface for platform-specific APIs.
|
|
40
|
+
*
|
|
41
|
+
* WebF types are provided by @openwebf/webf-enterprise-typings package.
|
|
42
|
+
* In browser environments, the router works without WebF types.
|
|
40
43
|
*/
|
|
41
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Get the WebF hybridHistory object if available
|
|
46
|
+
* Types come from @openwebf/webf-enterprise-typings peer dependency
|
|
47
|
+
*/
|
|
48
|
+
function getWebFHybridHistory() {
|
|
42
49
|
var _a;
|
|
43
50
|
return (_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.webf) === null || _a === void 0 ? void 0 : _a.hybridHistory;
|
|
44
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Detect the current platform
|
|
54
|
+
*/
|
|
55
|
+
function detectPlatform() {
|
|
56
|
+
// Check for WebF's hybridHistory API
|
|
57
|
+
if (getWebFHybridHistory()) {
|
|
58
|
+
return 'webf';
|
|
59
|
+
}
|
|
60
|
+
return 'browser';
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Check if running in WebF environment
|
|
64
|
+
*/
|
|
65
|
+
function isWebF() {
|
|
66
|
+
return detectPlatform() === 'webf';
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if running in browser environment
|
|
70
|
+
*/
|
|
71
|
+
function isBrowser() {
|
|
72
|
+
return detectPlatform() === 'browser';
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get the current platform type (evaluated once at module load)
|
|
76
|
+
*/
|
|
77
|
+
const platform = detectPlatform();
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Browser History Adapter
|
|
81
|
+
*
|
|
82
|
+
* Provides a unified history API that mimics WebF's hybridHistory
|
|
83
|
+
* but uses the standard browser History API under the hood.
|
|
84
|
+
*
|
|
85
|
+
* Supports SSR/Node.js environments by providing memory-based fallback.
|
|
86
|
+
*/
|
|
87
|
+
/**
|
|
88
|
+
* Check if we're in a browser environment
|
|
89
|
+
*/
|
|
90
|
+
function hasWindow() {
|
|
91
|
+
return typeof window !== 'undefined' && typeof window.history !== 'undefined';
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Generate a unique key for history entries
|
|
95
|
+
*/
|
|
96
|
+
function generateKey() {
|
|
97
|
+
return Math.random().toString(36).substring(2, 10);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Browser History implementation that provides WebF-like navigation APIs
|
|
101
|
+
*/
|
|
102
|
+
class BrowserHistoryAdapter {
|
|
103
|
+
constructor() {
|
|
104
|
+
this._stack = [];
|
|
105
|
+
this._currentIndex = -1;
|
|
106
|
+
this._listeners = new Set();
|
|
107
|
+
this._initialized = false;
|
|
108
|
+
this._initialize();
|
|
109
|
+
}
|
|
110
|
+
_initialize() {
|
|
111
|
+
if (this._initialized)
|
|
112
|
+
return;
|
|
113
|
+
this._initialized = true;
|
|
114
|
+
// SSR/Node.js fallback - use memory-based history
|
|
115
|
+
if (!hasWindow()) {
|
|
116
|
+
const key = generateKey();
|
|
117
|
+
this._stack = [{ path: '/', state: null, key }];
|
|
118
|
+
this._currentIndex = 0;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Initialize with current location
|
|
122
|
+
const initialPath = window.location.pathname || '/';
|
|
123
|
+
const initialState = window.history.state;
|
|
124
|
+
if (initialState === null || initialState === void 0 ? void 0 : initialState.key) {
|
|
125
|
+
// Restore from existing state
|
|
126
|
+
this._stack = [{ path: initialState.path, state: initialState.state, key: initialState.key }];
|
|
127
|
+
this._currentIndex = 0;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// Fresh start
|
|
131
|
+
const key = generateKey();
|
|
132
|
+
const entry = { path: initialPath, state: null, key };
|
|
133
|
+
this._stack = [entry];
|
|
134
|
+
this._currentIndex = 0;
|
|
135
|
+
// Replace current state with our tracked state
|
|
136
|
+
window.history.replaceState({ path: initialPath, state: null, key, index: 0 }, '', initialPath);
|
|
137
|
+
}
|
|
138
|
+
// Listen to popstate events
|
|
139
|
+
window.addEventListener('popstate', this._handlePopState.bind(this));
|
|
140
|
+
}
|
|
141
|
+
_handlePopState(event) {
|
|
142
|
+
const state = event.state;
|
|
143
|
+
if (state === null || state === void 0 ? void 0 : state.key) {
|
|
144
|
+
// Find the entry in our stack
|
|
145
|
+
const index = this._stack.findIndex((e) => e.key === state.key);
|
|
146
|
+
if (index !== -1) {
|
|
147
|
+
this._currentIndex = index;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Dispatch custom event for Routes component
|
|
151
|
+
this._dispatchRouterChangeEvent((state === null || state === void 0 ? void 0 : state.path) || window.location.pathname, state === null || state === void 0 ? void 0 : state.state, 'didPopNext');
|
|
152
|
+
}
|
|
153
|
+
_dispatchRouterChangeEvent(path, state, kind) {
|
|
154
|
+
if (typeof document === 'undefined')
|
|
155
|
+
return;
|
|
156
|
+
const event = new CustomEvent('hybridrouterchange', {
|
|
157
|
+
bubbles: true,
|
|
158
|
+
composed: true,
|
|
159
|
+
detail: { path, state, kind },
|
|
160
|
+
});
|
|
161
|
+
event.path = path;
|
|
162
|
+
event.state = state;
|
|
163
|
+
event.kind = kind;
|
|
164
|
+
document.dispatchEvent(event);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get the current state
|
|
168
|
+
*/
|
|
169
|
+
get state() {
|
|
170
|
+
var _a, _b;
|
|
171
|
+
return (_b = (_a = this._stack[this._currentIndex]) === null || _a === void 0 ? void 0 : _a.state) !== null && _b !== void 0 ? _b : null;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get the current path
|
|
175
|
+
*/
|
|
176
|
+
get path() {
|
|
177
|
+
var _a, _b;
|
|
178
|
+
return (_b = (_a = this._stack[this._currentIndex]) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : '/';
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get the full navigation stack
|
|
182
|
+
*/
|
|
183
|
+
get buildContextStack() {
|
|
184
|
+
// Return entries up to current index (simulating WebF's stack behavior)
|
|
185
|
+
return this._stack.slice(0, this._currentIndex + 1);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Push a new named route (WebF-style)
|
|
189
|
+
*/
|
|
190
|
+
pushNamed(path, options) {
|
|
191
|
+
var _a;
|
|
192
|
+
const key = generateKey();
|
|
193
|
+
const state = (_a = options === null || options === void 0 ? void 0 : options.arguments) !== null && _a !== void 0 ? _a : null;
|
|
194
|
+
const newIndex = this._currentIndex + 1;
|
|
195
|
+
// Truncate forward stack if we're in the middle
|
|
196
|
+
this._stack = this._stack.slice(0, newIndex);
|
|
197
|
+
const entry = { path, state, key };
|
|
198
|
+
this._stack.push(entry);
|
|
199
|
+
this._currentIndex = newIndex;
|
|
200
|
+
if (hasWindow()) {
|
|
201
|
+
window.history.pushState({ path, state, key, index: newIndex }, '', path);
|
|
202
|
+
}
|
|
203
|
+
this._dispatchRouterChangeEvent(path, state, 'didPush');
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Replace the current route (WebF-style)
|
|
207
|
+
*/
|
|
208
|
+
pushReplacementNamed(path, options) {
|
|
209
|
+
var _a;
|
|
210
|
+
const key = generateKey();
|
|
211
|
+
const state = (_a = options === null || options === void 0 ? void 0 : options.arguments) !== null && _a !== void 0 ? _a : null;
|
|
212
|
+
const entry = { path, state, key };
|
|
213
|
+
this._stack[this._currentIndex] = entry;
|
|
214
|
+
if (hasWindow()) {
|
|
215
|
+
window.history.replaceState({ path, state, key, index: this._currentIndex }, '', path);
|
|
216
|
+
}
|
|
217
|
+
this._dispatchRouterChangeEvent(path, state, 'didPush');
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Go back in history
|
|
221
|
+
*/
|
|
222
|
+
back() {
|
|
223
|
+
var _a;
|
|
224
|
+
if (hasWindow()) {
|
|
225
|
+
window.history.back();
|
|
226
|
+
}
|
|
227
|
+
else if (this._currentIndex > 0) {
|
|
228
|
+
// Memory-based fallback for SSR
|
|
229
|
+
this._currentIndex--;
|
|
230
|
+
const entry = this._stack[this._currentIndex];
|
|
231
|
+
this._dispatchRouterChangeEvent((_a = entry === null || entry === void 0 ? void 0 : entry.path) !== null && _a !== void 0 ? _a : '/', entry === null || entry === void 0 ? void 0 : entry.state, 'didPopNext');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Pop the current route (Flutter-style)
|
|
236
|
+
*/
|
|
237
|
+
pop(result) {
|
|
238
|
+
var _a;
|
|
239
|
+
if (this._currentIndex > 0) {
|
|
240
|
+
if (hasWindow()) {
|
|
241
|
+
window.history.back();
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
// Memory-based fallback for SSR
|
|
245
|
+
this._currentIndex--;
|
|
246
|
+
const entry = this._stack[this._currentIndex];
|
|
247
|
+
this._dispatchRouterChangeEvent((_a = entry === null || entry === void 0 ? void 0 : entry.path) !== null && _a !== void 0 ? _a : '/', entry === null || entry === void 0 ? void 0 : entry.state, 'didPopNext');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Pop routes until reaching a specific route
|
|
253
|
+
*/
|
|
254
|
+
popUntil(targetPath) {
|
|
255
|
+
var _a;
|
|
256
|
+
const targetIndex = this._stack.findIndex((e) => e.path === targetPath);
|
|
257
|
+
if (targetIndex !== -1 && targetIndex < this._currentIndex) {
|
|
258
|
+
if (hasWindow()) {
|
|
259
|
+
const delta = targetIndex - this._currentIndex;
|
|
260
|
+
window.history.go(delta);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
// Memory-based fallback for SSR
|
|
264
|
+
this._currentIndex = targetIndex;
|
|
265
|
+
const entry = this._stack[this._currentIndex];
|
|
266
|
+
this._dispatchRouterChangeEvent((_a = entry === null || entry === void 0 ? void 0 : entry.path) !== null && _a !== void 0 ? _a : '/', entry === null || entry === void 0 ? void 0 : entry.state, 'didPopNext');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Pop the current route and push a new route
|
|
272
|
+
*/
|
|
273
|
+
popAndPushNamed(path, options) {
|
|
274
|
+
var _a;
|
|
275
|
+
const key = generateKey();
|
|
276
|
+
const state = (_a = options === null || options === void 0 ? void 0 : options.arguments) !== null && _a !== void 0 ? _a : null;
|
|
277
|
+
const entry = { path, state, key };
|
|
278
|
+
this._stack[this._currentIndex] = entry;
|
|
279
|
+
if (hasWindow()) {
|
|
280
|
+
window.history.replaceState({ path, state, key, index: this._currentIndex }, '', path);
|
|
281
|
+
}
|
|
282
|
+
this._dispatchRouterChangeEvent(path, state, 'didPush');
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Push a new route and remove routes until a specific route
|
|
286
|
+
*/
|
|
287
|
+
pushNamedAndRemoveUntil(state, path, untilPath) {
|
|
288
|
+
const targetIndex = this._stack.findIndex((e) => e.path === untilPath);
|
|
289
|
+
if (targetIndex !== -1) {
|
|
290
|
+
// Truncate stack to target and add new entry
|
|
291
|
+
this._stack = this._stack.slice(0, targetIndex + 1);
|
|
292
|
+
this._currentIndex = targetIndex;
|
|
293
|
+
}
|
|
294
|
+
this.pushNamed(path, { arguments: state });
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Push a new route and remove all routes until a specific route (Flutter-style)
|
|
298
|
+
*/
|
|
299
|
+
pushNamedAndRemoveUntilRoute(newPath, untilPath, options) {
|
|
300
|
+
this.pushNamedAndRemoveUntil(options === null || options === void 0 ? void 0 : options.arguments, newPath, untilPath);
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Check if we can go back
|
|
304
|
+
*/
|
|
305
|
+
canPop() {
|
|
306
|
+
return this._currentIndex > 0;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Pop if possible, return success status
|
|
310
|
+
*/
|
|
311
|
+
maybePop(result) {
|
|
312
|
+
if (this.canPop()) {
|
|
313
|
+
this.pop(result);
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Push state (web-style)
|
|
320
|
+
*/
|
|
321
|
+
pushState(state, name) {
|
|
322
|
+
this.pushNamed(name, { arguments: state });
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Replace state (web-style)
|
|
326
|
+
*/
|
|
327
|
+
replaceState(state, name) {
|
|
328
|
+
this.pushReplacementNamed(name, { arguments: state });
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Pop and push with restoration capability
|
|
332
|
+
*/
|
|
333
|
+
restorablePopAndPushState(state, name) {
|
|
334
|
+
const key = generateKey();
|
|
335
|
+
this.popAndPushNamed(name, { arguments: state });
|
|
336
|
+
return key;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Pop and push named route with restoration capability
|
|
340
|
+
*/
|
|
341
|
+
restorablePopAndPushNamed(path, options) {
|
|
342
|
+
const key = generateKey();
|
|
343
|
+
this.popAndPushNamed(path, options);
|
|
344
|
+
return key;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// Singleton instance
|
|
348
|
+
let browserHistoryInstance = null;
|
|
349
|
+
/**
|
|
350
|
+
* Get the browser history adapter instance
|
|
351
|
+
*/
|
|
352
|
+
function getBrowserHistory() {
|
|
353
|
+
if (!browserHistoryInstance) {
|
|
354
|
+
browserHistoryInstance = new BrowserHistoryAdapter();
|
|
355
|
+
}
|
|
356
|
+
return browserHistoryInstance;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Reset the browser history adapter (for testing)
|
|
360
|
+
*/
|
|
361
|
+
function resetBrowserHistory() {
|
|
362
|
+
browserHistoryInstance = null;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Get the appropriate history object based on the current platform.
|
|
367
|
+
* Returns WebF's hybridHistory in WebF environment, or BrowserHistoryAdapter in browser.
|
|
368
|
+
*/
|
|
369
|
+
function getHybridHistory() {
|
|
370
|
+
const webfHistory = getWebFHybridHistory();
|
|
371
|
+
if (webfHistory) {
|
|
372
|
+
return webfHistory;
|
|
373
|
+
}
|
|
374
|
+
// Fallback to browser history adapter
|
|
375
|
+
return getBrowserHistory();
|
|
376
|
+
}
|
|
45
377
|
let ensureRouteMountedCallback = null;
|
|
46
378
|
function __unstable_setEnsureRouteMountedCallback(callback) {
|
|
47
379
|
ensureRouteMountedCallback = callback;
|
|
@@ -55,7 +387,8 @@ function ensureRouteMounted(pathname) {
|
|
|
55
387
|
}
|
|
56
388
|
/**
|
|
57
389
|
* WebF Router object - provides comprehensive navigation APIs
|
|
58
|
-
* Combines web-like history management with Flutter-like navigation patterns
|
|
390
|
+
* Combines web-like history management with Flutter-like navigation patterns.
|
|
391
|
+
* Works in both WebF native environment and standard browser environment.
|
|
59
392
|
*/
|
|
60
393
|
const WebFRouter = {
|
|
61
394
|
/**
|
|
@@ -86,8 +419,6 @@ const WebFRouter = {
|
|
|
86
419
|
*/
|
|
87
420
|
push: (path, state) => __awaiter(void 0, void 0, void 0, function* () {
|
|
88
421
|
const hybridHistory = getHybridHistory();
|
|
89
|
-
if (!hybridHistory)
|
|
90
|
-
throw new Error('WebF hybridHistory is not available');
|
|
91
422
|
yield ensureRouteMounted(path);
|
|
92
423
|
hybridHistory.pushNamed(path, { arguments: state });
|
|
93
424
|
}),
|
|
@@ -97,8 +428,6 @@ const WebFRouter = {
|
|
|
97
428
|
*/
|
|
98
429
|
replace: (path, state) => __awaiter(void 0, void 0, void 0, function* () {
|
|
99
430
|
const hybridHistory = getHybridHistory();
|
|
100
|
-
if (!hybridHistory)
|
|
101
|
-
throw new Error('WebF hybridHistory is not available');
|
|
102
431
|
yield ensureRouteMounted(path);
|
|
103
432
|
hybridHistory.pushReplacementNamed(path, { arguments: state });
|
|
104
433
|
}),
|
|
@@ -107,8 +436,6 @@ const WebFRouter = {
|
|
|
107
436
|
*/
|
|
108
437
|
back: () => {
|
|
109
438
|
const hybridHistory = getHybridHistory();
|
|
110
|
-
if (!hybridHistory)
|
|
111
|
-
throw new Error('WebF hybridHistory is not available');
|
|
112
439
|
hybridHistory.back();
|
|
113
440
|
},
|
|
114
441
|
/**
|
|
@@ -117,8 +444,6 @@ const WebFRouter = {
|
|
|
117
444
|
*/
|
|
118
445
|
pop: (result) => {
|
|
119
446
|
const hybridHistory = getHybridHistory();
|
|
120
|
-
if (!hybridHistory)
|
|
121
|
-
throw new Error('WebF hybridHistory is not available');
|
|
122
447
|
hybridHistory.pop(result);
|
|
123
448
|
},
|
|
124
449
|
/**
|
|
@@ -126,8 +451,6 @@ const WebFRouter = {
|
|
|
126
451
|
*/
|
|
127
452
|
popUntil: (path) => {
|
|
128
453
|
const hybridHistory = getHybridHistory();
|
|
129
|
-
if (!hybridHistory)
|
|
130
|
-
throw new Error('WebF hybridHistory is not available');
|
|
131
454
|
hybridHistory.popUntil(path);
|
|
132
455
|
},
|
|
133
456
|
/**
|
|
@@ -135,8 +458,6 @@ const WebFRouter = {
|
|
|
135
458
|
*/
|
|
136
459
|
popAndPushNamed: (path, state) => __awaiter(void 0, void 0, void 0, function* () {
|
|
137
460
|
const hybridHistory = getHybridHistory();
|
|
138
|
-
if (!hybridHistory)
|
|
139
|
-
throw new Error('WebF hybridHistory is not available');
|
|
140
461
|
yield ensureRouteMounted(path);
|
|
141
462
|
hybridHistory.popAndPushNamed(path, { arguments: state });
|
|
142
463
|
}),
|
|
@@ -145,8 +466,6 @@ const WebFRouter = {
|
|
|
145
466
|
*/
|
|
146
467
|
pushNamedAndRemoveUntil: (path, state, untilPath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
147
468
|
const hybridHistory = getHybridHistory();
|
|
148
|
-
if (!hybridHistory)
|
|
149
|
-
throw new Error('WebF hybridHistory is not available');
|
|
150
469
|
yield ensureRouteMounted(path);
|
|
151
470
|
hybridHistory.pushNamedAndRemoveUntil(state, path, untilPath);
|
|
152
471
|
}),
|
|
@@ -155,8 +474,6 @@ const WebFRouter = {
|
|
|
155
474
|
*/
|
|
156
475
|
pushNamedAndRemoveUntilRoute: (newPath, untilPath, state) => __awaiter(void 0, void 0, void 0, function* () {
|
|
157
476
|
const hybridHistory = getHybridHistory();
|
|
158
|
-
if (!hybridHistory)
|
|
159
|
-
throw new Error('WebF hybridHistory is not available');
|
|
160
477
|
yield ensureRouteMounted(newPath);
|
|
161
478
|
hybridHistory.pushNamedAndRemoveUntilRoute(newPath, untilPath, { arguments: state });
|
|
162
479
|
}),
|
|
@@ -165,8 +482,6 @@ const WebFRouter = {
|
|
|
165
482
|
*/
|
|
166
483
|
canPop: () => {
|
|
167
484
|
const hybridHistory = getHybridHistory();
|
|
168
|
-
if (!hybridHistory)
|
|
169
|
-
return false;
|
|
170
485
|
return hybridHistory.canPop();
|
|
171
486
|
},
|
|
172
487
|
/**
|
|
@@ -175,8 +490,6 @@ const WebFRouter = {
|
|
|
175
490
|
*/
|
|
176
491
|
maybePop: (result) => {
|
|
177
492
|
const hybridHistory = getHybridHistory();
|
|
178
|
-
if (!hybridHistory)
|
|
179
|
-
return false;
|
|
180
493
|
return hybridHistory.maybePop(result);
|
|
181
494
|
},
|
|
182
495
|
/**
|
|
@@ -184,8 +497,6 @@ const WebFRouter = {
|
|
|
184
497
|
*/
|
|
185
498
|
pushState: (state, name) => {
|
|
186
499
|
const hybridHistory = getHybridHistory();
|
|
187
|
-
if (!hybridHistory)
|
|
188
|
-
throw new Error('WebF hybridHistory is not available');
|
|
189
500
|
hybridHistory.pushState(state, name);
|
|
190
501
|
},
|
|
191
502
|
/**
|
|
@@ -193,8 +504,6 @@ const WebFRouter = {
|
|
|
193
504
|
*/
|
|
194
505
|
replaceState: (state, name) => {
|
|
195
506
|
const hybridHistory = getHybridHistory();
|
|
196
|
-
if (!hybridHistory)
|
|
197
|
-
throw new Error('WebF hybridHistory is not available');
|
|
198
507
|
hybridHistory.replaceState(state, name);
|
|
199
508
|
},
|
|
200
509
|
/**
|
|
@@ -203,8 +512,6 @@ const WebFRouter = {
|
|
|
203
512
|
*/
|
|
204
513
|
restorablePopAndPushState: (state, name) => {
|
|
205
514
|
const hybridHistory = getHybridHistory();
|
|
206
|
-
if (!hybridHistory)
|
|
207
|
-
throw new Error('WebF hybridHistory is not available');
|
|
208
515
|
return hybridHistory.restorablePopAndPushState(state, name);
|
|
209
516
|
},
|
|
210
517
|
/**
|
|
@@ -213,8 +520,6 @@ const WebFRouter = {
|
|
|
213
520
|
*/
|
|
214
521
|
restorablePopAndPushNamed: (path, state) => __awaiter(void 0, void 0, void 0, function* () {
|
|
215
522
|
const hybridHistory = getHybridHistory();
|
|
216
|
-
if (!hybridHistory)
|
|
217
|
-
throw new Error('WebF hybridHistory is not available');
|
|
218
523
|
yield ensureRouteMounted(path);
|
|
219
524
|
return hybridHistory.restorablePopAndPushNamed(path, { arguments: state });
|
|
220
525
|
})
|
|
@@ -317,41 +622,183 @@ var useMemoizedFn = function (fn) {
|
|
|
317
622
|
return memoizedFn.current;
|
|
318
623
|
};
|
|
319
624
|
|
|
320
|
-
//
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
625
|
+
// Conditionally import createWebFComponent only when needed
|
|
626
|
+
let createWebFComponent = null;
|
|
627
|
+
let WebFElementWithMethods = null;
|
|
628
|
+
// Try to import @openwebf/react-core-ui, but don't fail if it's not available in browser
|
|
629
|
+
try {
|
|
630
|
+
const coreUi = require("@openwebf/react-core-ui");
|
|
631
|
+
createWebFComponent = coreUi.createWebFComponent;
|
|
632
|
+
WebFElementWithMethods = coreUi.WebFElementWithMethods;
|
|
633
|
+
}
|
|
634
|
+
catch (e) {
|
|
635
|
+
// In browser environment without @openwebf/react-core-ui, we'll use the fallback
|
|
636
|
+
}
|
|
637
|
+
// Lazily create the WebF component only when needed
|
|
638
|
+
let RawWebFRouterLink = null;
|
|
639
|
+
function getRawWebFRouterLink() {
|
|
640
|
+
if (RawWebFRouterLink)
|
|
641
|
+
return RawWebFRouterLink;
|
|
642
|
+
if (!createWebFComponent) {
|
|
643
|
+
throw new Error('@openwebf/react-core-ui is required in WebF environment');
|
|
644
|
+
}
|
|
645
|
+
RawWebFRouterLink = createWebFComponent({
|
|
646
|
+
tagName: 'webf-router-link',
|
|
647
|
+
displayName: 'WebFRouterLink',
|
|
648
|
+
// Map props to attributes
|
|
649
|
+
attributeProps: ['path', 'title', 'theme'],
|
|
650
|
+
// Event handlers
|
|
651
|
+
events: [
|
|
652
|
+
{
|
|
653
|
+
propName: 'onScreen',
|
|
654
|
+
eventName: 'onscreen',
|
|
655
|
+
handler: (callback) => (event) => {
|
|
656
|
+
callback(event);
|
|
657
|
+
},
|
|
334
658
|
},
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
callback(event);
|
|
659
|
+
{
|
|
660
|
+
propName: 'offScreen',
|
|
661
|
+
eventName: 'offscreen',
|
|
662
|
+
handler: (callback) => (event) => {
|
|
663
|
+
callback(event);
|
|
664
|
+
},
|
|
342
665
|
},
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
666
|
+
{
|
|
667
|
+
propName: 'onPrerendering',
|
|
668
|
+
eventName: 'prerendering',
|
|
669
|
+
handler: (callback) => (event) => {
|
|
670
|
+
callback(event);
|
|
671
|
+
},
|
|
349
672
|
},
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
673
|
+
],
|
|
674
|
+
});
|
|
675
|
+
return RawWebFRouterLink;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Browser-based RouterLink implementation
|
|
679
|
+
* Used when running in standard browser environment instead of WebF
|
|
680
|
+
*/
|
|
681
|
+
const BrowserRouterLink = function (props) {
|
|
682
|
+
const [isActive, setIsActive] = useState(false);
|
|
683
|
+
const [isRender, setIsRender] = useState(false);
|
|
684
|
+
const hasTriggeredOnScreen = useRef(false);
|
|
685
|
+
useEffect(() => {
|
|
686
|
+
const browserHistory = getBrowserHistory();
|
|
687
|
+
const currentPath = browserHistory.path;
|
|
688
|
+
// Check if this route matches the current path
|
|
689
|
+
const isCurrentlyActive = currentPath === props.path;
|
|
690
|
+
setIsActive(isCurrentlyActive);
|
|
691
|
+
if (isCurrentlyActive && !hasTriggeredOnScreen.current) {
|
|
692
|
+
hasTriggeredOnScreen.current = true;
|
|
693
|
+
setIsRender(true);
|
|
694
|
+
// Create a synthetic event for onScreen callback
|
|
695
|
+
if (props.onScreen) {
|
|
696
|
+
const syntheticEvent = {
|
|
697
|
+
state: browserHistory.state,
|
|
698
|
+
kind: 'didPush',
|
|
699
|
+
path: props.path,
|
|
700
|
+
nativeEvent: new Event('onscreen'),
|
|
701
|
+
currentTarget: null,
|
|
702
|
+
target: null,
|
|
703
|
+
bubbles: true,
|
|
704
|
+
cancelable: false,
|
|
705
|
+
defaultPrevented: false,
|
|
706
|
+
eventPhase: 0,
|
|
707
|
+
isTrusted: true,
|
|
708
|
+
preventDefault: () => { },
|
|
709
|
+
isDefaultPrevented: () => false,
|
|
710
|
+
stopPropagation: () => { },
|
|
711
|
+
isPropagationStopped: () => false,
|
|
712
|
+
persist: () => { },
|
|
713
|
+
timeStamp: Date.now(),
|
|
714
|
+
type: 'onscreen',
|
|
715
|
+
};
|
|
716
|
+
props.onScreen(syntheticEvent);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
// Listen for route changes
|
|
720
|
+
const handleRouteChange = (event) => {
|
|
721
|
+
var _a, _b, _c, _d, _e;
|
|
722
|
+
const customEvent = event;
|
|
723
|
+
const newPath = ((_a = customEvent.detail) === null || _a === void 0 ? void 0 : _a.path) || event.path;
|
|
724
|
+
const newIsActive = newPath === props.path;
|
|
725
|
+
if (newIsActive && !isActive) {
|
|
726
|
+
// Route became active
|
|
727
|
+
hasTriggeredOnScreen.current = true;
|
|
728
|
+
setIsRender(true);
|
|
729
|
+
setIsActive(true);
|
|
730
|
+
if (props.onScreen) {
|
|
731
|
+
const syntheticEvent = {
|
|
732
|
+
state: ((_b = customEvent.detail) === null || _b === void 0 ? void 0 : _b.state) || event.state,
|
|
733
|
+
kind: (((_c = customEvent.detail) === null || _c === void 0 ? void 0 : _c.kind) || event.kind),
|
|
734
|
+
path: newPath,
|
|
735
|
+
nativeEvent: event,
|
|
736
|
+
currentTarget: event.currentTarget,
|
|
737
|
+
target: event.target,
|
|
738
|
+
bubbles: true,
|
|
739
|
+
cancelable: false,
|
|
740
|
+
defaultPrevented: false,
|
|
741
|
+
eventPhase: 0,
|
|
742
|
+
isTrusted: true,
|
|
743
|
+
preventDefault: () => { },
|
|
744
|
+
isDefaultPrevented: () => false,
|
|
745
|
+
stopPropagation: () => { },
|
|
746
|
+
isPropagationStopped: () => false,
|
|
747
|
+
persist: () => { },
|
|
748
|
+
timeStamp: Date.now(),
|
|
749
|
+
type: 'onscreen',
|
|
750
|
+
};
|
|
751
|
+
props.onScreen(syntheticEvent);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
else if (!newIsActive && isActive) {
|
|
755
|
+
// Route became inactive
|
|
756
|
+
setIsActive(false);
|
|
757
|
+
if (props.offScreen) {
|
|
758
|
+
const syntheticEvent = {
|
|
759
|
+
state: ((_d = customEvent.detail) === null || _d === void 0 ? void 0 : _d.state) || event.state,
|
|
760
|
+
kind: (((_e = customEvent.detail) === null || _e === void 0 ? void 0 : _e.kind) || event.kind),
|
|
761
|
+
path: newPath,
|
|
762
|
+
nativeEvent: event,
|
|
763
|
+
currentTarget: event.currentTarget,
|
|
764
|
+
target: event.target,
|
|
765
|
+
bubbles: true,
|
|
766
|
+
cancelable: false,
|
|
767
|
+
defaultPrevented: false,
|
|
768
|
+
eventPhase: 0,
|
|
769
|
+
isTrusted: true,
|
|
770
|
+
preventDefault: () => { },
|
|
771
|
+
isDefaultPrevented: () => false,
|
|
772
|
+
stopPropagation: () => { },
|
|
773
|
+
isPropagationStopped: () => false,
|
|
774
|
+
persist: () => { },
|
|
775
|
+
timeStamp: Date.now(),
|
|
776
|
+
type: 'offscreen',
|
|
777
|
+
};
|
|
778
|
+
props.offScreen(syntheticEvent);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
document.addEventListener('hybridrouterchange', handleRouteChange);
|
|
783
|
+
return () => {
|
|
784
|
+
document.removeEventListener('hybridrouterchange', handleRouteChange);
|
|
785
|
+
};
|
|
786
|
+
}, [props.path, props.onScreen, props.offScreen, isActive]);
|
|
787
|
+
// In browser mode, we render a div that acts as a route container
|
|
788
|
+
// Only show content when route is rendered (similar to WebF behavior)
|
|
789
|
+
return (React.createElement("div", { "data-path": props.path, "data-title": props.title, style: {
|
|
790
|
+
display: isActive ? 'block' : 'none',
|
|
791
|
+
width: '100%',
|
|
792
|
+
height: '100%',
|
|
793
|
+
} }, isRender ? props.children : null));
|
|
794
|
+
};
|
|
795
|
+
/**
|
|
796
|
+
* WebF RouterLink implementation
|
|
797
|
+
* Used in WebF native environment
|
|
798
|
+
*/
|
|
799
|
+
const WebFNativeRouterLink = function (props) {
|
|
354
800
|
const [isRender, enableRender] = useState(false);
|
|
801
|
+
const RawComponent = getRawWebFRouterLink();
|
|
355
802
|
const handleOnScreen = (event) => {
|
|
356
803
|
enableRender(true);
|
|
357
804
|
if (props.onScreen) {
|
|
@@ -363,7 +810,18 @@ const WebFRouterLink = function (props) {
|
|
|
363
810
|
enableRender(true);
|
|
364
811
|
(_a = props.onPrerendering) === null || _a === void 0 ? void 0 : _a.call(props, event);
|
|
365
812
|
};
|
|
366
|
-
return (React.createElement(
|
|
813
|
+
return (React.createElement(RawComponent, { title: props.title, path: props.path, theme: props.theme, onScreen: handleOnScreen, offScreen: props.offScreen, onPrerendering: handlePrerendering }, isRender ? props.children : null));
|
|
814
|
+
};
|
|
815
|
+
/**
|
|
816
|
+
* Unified RouterLink component that works in both WebF and browser environments
|
|
817
|
+
*/
|
|
818
|
+
const WebFRouterLink = function (props) {
|
|
819
|
+
// Use WebF native implementation if in WebF environment
|
|
820
|
+
if (isWebF()) {
|
|
821
|
+
return React.createElement(WebFNativeRouterLink, Object.assign({}, props));
|
|
822
|
+
}
|
|
823
|
+
// Use browser-based implementation
|
|
824
|
+
return React.createElement(BrowserRouterLink, Object.assign({}, props));
|
|
367
825
|
};
|
|
368
826
|
|
|
369
827
|
/**
|
|
@@ -825,5 +1283,5 @@ function useNavigate() {
|
|
|
825
1283
|
}, []);
|
|
826
1284
|
}
|
|
827
1285
|
|
|
828
|
-
export { Route, Routes, WebFRouter, WebFRouterLink, __unstable_setEnsureRouteMountedCallback, matchPath, matchRoutes, pathToRegex, useLocation, useNavigate, useParams, useRouteContext, useRoutes };
|
|
1286
|
+
export { Route, Routes, WebFRouter, WebFRouterLink, __unstable_setEnsureRouteMountedCallback, detectPlatform, isBrowser, isWebF, matchPath, matchRoutes, pathToRegex, platform, resetBrowserHistory, useLocation, useNavigate, useParams, useRouteContext, useRoutes };
|
|
829
1287
|
//# sourceMappingURL=index.esm.js.map
|