@openwebf/react-router 0.24.2 → 1.0.1

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