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