@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.esm.js CHANGED
@@ -1,5 +1,4 @@
1
- import React, { useRef, useMemo, useState, createContext, useContext, useEffect, Children, isValidElement } from 'react';
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
- * Router management module
36
+ * Platform detection and abstraction layer
38
37
  *
39
- * Encapsulates routing navigation functionality with route guard mechanism for permission checks
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
- function getHybridHistory() {
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
- // Create the raw component using createWebFComponent
321
- const RawWebFRouterLink = createWebFComponent({
322
- tagName: 'webf-router-link',
323
- displayName: 'WebFRouterLink',
324
- // Map props to attributes
325
- attributeProps: ['path', 'title', 'theme'],
326
- // Event handlers
327
- events: [
328
- {
329
- propName: 'onScreen',
330
- eventName: 'onscreen',
331
- handler: (callback) => (event) => {
332
- // Cast through unknown first for proper type conversion
333
- callback(event);
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
- propName: 'offScreen',
338
- eventName: 'offscreen',
339
- handler: (callback) => (event) => {
340
- // Cast through unknown first for proper type conversion
341
- callback(event);
659
+ {
660
+ propName: 'offScreen',
661
+ eventName: 'offscreen',
662
+ handler: (callback) => (event) => {
663
+ callback(event);
664
+ },
342
665
  },
343
- },
344
- {
345
- propName: 'onPrerendering',
346
- eventName: 'prerendering',
347
- handler: (callback) => (event) => {
348
- callback(event);
666
+ {
667
+ propName: 'onPrerendering',
668
+ eventName: 'prerendering',
669
+ handler: (callback) => (event) => {
670
+ callback(event);
671
+ },
349
672
  },
350
- },
351
- ],
352
- });
353
- const WebFRouterLink = function (props) {
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(RawWebFRouterLink, { title: props.title, path: props.path, theme: props.theme, onScreen: handleOnScreen, offScreen: props.offScreen, onPrerendering: handlePrerendering }, isRender ? props.children : null));
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