@omerdlw/base-framework 2.0.1 → 3.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.
Files changed (94) hide show
  1. package/README.md +4 -1
  2. package/dist/{chunk-XASQT4CQ.js → chunk-66EYJBIP.js} +47 -27
  3. package/dist/chunk-66EYJBIP.js.map +1 -0
  4. package/dist/{chunk-SKBITB5X.js → chunk-CYU6SGAL.js} +3 -3
  5. package/dist/{chunk-SKBITB5X.js.map → chunk-CYU6SGAL.js.map} +1 -1
  6. package/dist/{chunk-6SG7V77J.js → chunk-HHWRTQKQ.js} +100 -67
  7. package/dist/chunk-HHWRTQKQ.js.map +1 -0
  8. package/dist/chunk-HLL5EHXC.js +485 -0
  9. package/dist/chunk-HLL5EHXC.js.map +1 -0
  10. package/dist/{chunk-A5RE3F6O.js → chunk-JIXBFFRD.js} +193 -357
  11. package/dist/chunk-JIXBFFRD.js.map +1 -0
  12. package/dist/{chunk-6ZJVLUBE.js → chunk-M57SNWXK.js} +8 -6
  13. package/dist/chunk-M57SNWXK.js.map +1 -0
  14. package/dist/chunk-RIOKLMYM.js +145 -0
  15. package/dist/chunk-RIOKLMYM.js.map +1 -0
  16. package/dist/{chunk-QXR55VVS.js → chunk-TG6NMHXI.js} +241 -162
  17. package/dist/chunk-TG6NMHXI.js.map +1 -0
  18. package/dist/index.js +7 -5
  19. package/dist/modules/ambient/analyze.d.ts +18 -3
  20. package/dist/modules/ambient/analyze.d.ts.map +1 -1
  21. package/dist/modules/ambient/dom.d.ts +14 -1
  22. package/dist/modules/ambient/dom.d.ts.map +1 -1
  23. package/dist/modules/ambient/hooks.d.ts.map +1 -1
  24. package/dist/modules/ambient/index.d.ts +2 -2
  25. package/dist/modules/ambient/index.d.ts.map +1 -1
  26. package/dist/modules/ambient/index.js +1 -1
  27. package/dist/modules/ambient/server/index.d.ts +1 -1
  28. package/dist/modules/ambient/server/index.d.ts.map +1 -1
  29. package/dist/modules/ambient/server/index.js +2 -2
  30. package/dist/modules/ambient/server/index.js.map +1 -1
  31. package/dist/modules/ambient/settings.d.ts +1 -0
  32. package/dist/modules/ambient/settings.d.ts.map +1 -1
  33. package/dist/modules/ambient/types.d.ts +13 -0
  34. package/dist/modules/ambient/types.d.ts.map +1 -1
  35. package/dist/modules/ambient/worker/index.js +1 -1
  36. package/dist/modules/context-menu/index.js +4 -3
  37. package/dist/modules/dock/cards.d.ts.map +1 -1
  38. package/dist/modules/dock/constants.d.ts +1 -20
  39. package/dist/modules/dock/constants.d.ts.map +1 -1
  40. package/dist/modules/dock/index.js +3 -2
  41. package/dist/modules/dock/routing/guards.d.ts +1 -1
  42. package/dist/modules/dock/routing/navigation.d.ts +7 -4
  43. package/dist/modules/dock/routing/navigation.d.ts.map +1 -1
  44. package/dist/modules/dock/runtime/display.d.ts +31 -2
  45. package/dist/modules/dock/runtime/display.d.ts.map +1 -1
  46. package/dist/modules/dock/runtime/dock.d.ts +2 -2
  47. package/dist/modules/dock/runtime/dock.d.ts.map +1 -1
  48. package/dist/modules/dock/types.d.ts +5 -27
  49. package/dist/modules/dock/types.d.ts.map +1 -1
  50. package/dist/modules/index.d.ts +3 -2
  51. package/dist/modules/index.d.ts.map +1 -1
  52. package/dist/modules/index.js +7 -5
  53. package/dist/modules/loading/context.d.ts.map +1 -1
  54. package/dist/modules/loading/index.js +1 -1
  55. package/dist/modules/navigation/constants.d.ts +37 -0
  56. package/dist/modules/navigation/constants.d.ts.map +1 -0
  57. package/dist/modules/navigation/context.d.ts +10 -0
  58. package/dist/modules/navigation/context.d.ts.map +1 -0
  59. package/dist/modules/navigation/hooks.d.ts +29 -0
  60. package/dist/modules/navigation/hooks.d.ts.map +1 -0
  61. package/dist/modules/navigation/index.d.ts +10 -0
  62. package/dist/modules/navigation/index.d.ts.map +1 -0
  63. package/dist/modules/navigation/index.js +81 -0
  64. package/dist/modules/navigation/index.js.map +1 -0
  65. package/dist/modules/navigation/listeners.d.ts +15 -0
  66. package/dist/modules/navigation/listeners.d.ts.map +1 -0
  67. package/dist/modules/navigation/module.d.ts +25 -0
  68. package/dist/modules/navigation/module.d.ts.map +1 -0
  69. package/dist/modules/navigation/navigator.d.ts +8 -0
  70. package/dist/modules/navigation/navigator.d.ts.map +1 -0
  71. package/dist/modules/navigation/settings.d.ts +10 -0
  72. package/dist/modules/navigation/settings.d.ts.map +1 -0
  73. package/dist/modules/navigation/state.d.ts +20 -0
  74. package/dist/modules/navigation/state.d.ts.map +1 -0
  75. package/dist/modules/navigation/types.d.ts +168 -0
  76. package/dist/modules/navigation/types.d.ts.map +1 -0
  77. package/dist/modules/navigation/utils.d.ts +11 -0
  78. package/dist/modules/navigation/utils.d.ts.map +1 -0
  79. package/docs/getting-started.md +2 -0
  80. package/docs/modules/README.md +5 -1
  81. package/docs/modules/ambient.md +9 -6
  82. package/docs/modules/dock.md +12 -10
  83. package/docs/modules/loading.md +2 -2
  84. package/docs/modules/navigation.md +216 -0
  85. package/docs/proposals/navigation.md +209 -0
  86. package/package.json +6 -1
  87. package/templates/AGENTS.md +2 -0
  88. package/dist/chunk-6SG7V77J.js.map +0 -1
  89. package/dist/chunk-6ZJVLUBE.js.map +0 -1
  90. package/dist/chunk-A5RE3F6O.js.map +0 -1
  91. package/dist/chunk-QXR55VVS.js.map +0 -1
  92. package/dist/chunk-XASQT4CQ.js.map +0 -1
  93. package/dist/modules/dock/routing/transactions.d.ts +0 -21
  94. package/dist/modules/dock/routing/transactions.d.ts.map +0 -1
@@ -1,9 +1,10 @@
1
+ import { NAVIGATION_STATUS, createNavigator } from './chunk-HLL5EHXC.js';
1
2
  import { Z_INDEX } from './chunk-QI3ALLIB.js';
2
3
  import { useNotificationVisible } from './chunk-SYAVGTOX.js';
3
4
  import { useOptionalMediaState, useOptionalMediaActions } from './chunk-R2YGFJDJ.js';
4
- import { useOptionalLoadingActions, useOptionalLoadingState } from './chunk-XASQT4CQ.js';
5
+ import { useOptionalLoadingActions, useOptionalLoadingState } from './chunk-66EYJBIP.js';
5
6
  import { defineThemeSpec, useModuleMotion, useTheme, cssTransition, staggerDelay, gpuTransform, useOptionalModuleMotion } from './chunk-7TAVYJ3A.js';
6
- import { getOrCreateGlobalContext, defineModule, useRegistryEntries, useModuleRegistration } from './chunk-GF7TUX5I.js';
7
+ import { getOrCreateGlobalContext, defineModule, useModule, useRegistryEntries, useModuleRegistration } from './chunk-GF7TUX5I.js';
7
8
  import { createStore, cn, isImageIconSource, clamp, useIsomorphicLayoutEffect, isObject, isPlainObject, trimToNull, shallowEqual, useGlobalEvent, useRequiredContext, globalEvents, toArray, useIsFullscreenStateActive, useClickOutside, report, normalizePath, useStore, createScheduler, EVENT_TYPES, toUserMessage } from './chunk-TV3WEF5G.js';
8
9
  import { Tooltip, Icon, Button, Spinner } from './chunk-3BUP64Q6.js';
9
10
  import React, { createContext, memo, createElement, isValidElement, cloneElement, Suspense, useEffect, useState, useCallback, useMemo, use, useSyncExternalStore, useRef, useLayoutEffect, useReducer, lazy, useContext, useId } from 'react';
@@ -436,27 +437,8 @@ var DOCK_CARD_LAYOUT = Object.freeze({
436
437
  actionGap: DOCK_CARD_DIMENSIONS.actionGap,
437
438
  baseHeight: DOCK_CARD_DIMENSIONS.height
438
439
  });
439
- var DOCK_TRANSACTION_EVENTS = Object.freeze({
440
- START: "START",
441
- COMPLETE: "COMPLETE",
442
- CANCEL: "CANCEL",
443
- FAIL: "FAIL",
444
- TIME_OUT: "TIME_OUT"
445
- });
446
- var DOCK_TRANSACTION_STATUS = Object.freeze({
447
- PENDING: "pending",
448
- COMPLETED: "completed",
449
- CANCELLED: "cancelled",
450
- FAILED: "failed",
451
- TIMED_OUT: "timed-out"
452
- });
453
- var DOCK_TRANSACTION_REASON = Object.freeze({
454
- GUARD: "guard",
455
- SUPERSEDED: "superseded",
456
- TIME_OUT: "time-out"
457
- });
458
- var DOCK_TRANSACTION_TIMEOUT_MS = 15e3;
459
440
  var DOCK_PREFETCH_INTENT_DELAY_MS = 90;
441
+ var DOCK_PENDING_ROUTE_HOLD_MS = 2500;
460
442
  var DOCK_CONTINUITY_EVENTS = Object.freeze({
461
443
  CLEAR: "CLEAR",
462
444
  CONSUME_RETURN: "CONSUME_RETURN",
@@ -3027,210 +3009,6 @@ function openDockGuardConfirmation({
3027
3009
  }
3028
3010
  });
3029
3011
  }
3030
- function createDockTransactionState() {
3031
- return { active: null, last: null };
3032
- }
3033
- function createDockTransaction({
3034
- from = "",
3035
- id,
3036
- source = "dock",
3037
- startedAt = Date.now(),
3038
- to = ""
3039
- }) {
3040
- return {
3041
- from: String(from || ""),
3042
- id,
3043
- source,
3044
- startedAt,
3045
- status: DOCK_TRANSACTION_STATUS.PENDING,
3046
- to: String(to || "")
3047
- };
3048
- }
3049
- function settleDockTransaction(transaction, action, status) {
3050
- return {
3051
- ...transaction,
3052
- endedAt: action.endedAt ?? Date.now(),
3053
- error: action.error ?? null,
3054
- reason: action.reason ?? null,
3055
- status
3056
- };
3057
- }
3058
- var TRANSACTION_STATUS_MAP = Object.freeze({
3059
- [DOCK_TRANSACTION_EVENTS.COMPLETE]: DOCK_TRANSACTION_STATUS.COMPLETED,
3060
- [DOCK_TRANSACTION_EVENTS.CANCEL]: DOCK_TRANSACTION_STATUS.CANCELLED,
3061
- [DOCK_TRANSACTION_EVENTS.FAIL]: DOCK_TRANSACTION_STATUS.FAILED,
3062
- [DOCK_TRANSACTION_EVENTS.TIME_OUT]: DOCK_TRANSACTION_STATUS.TIMED_OUT
3063
- });
3064
- function dockTransactionReducer(state, action) {
3065
- if (action?.type === DOCK_TRANSACTION_EVENTS.START) {
3066
- const nextTransaction = action.transaction;
3067
- if (nextTransaction?.id == null) return state;
3068
- const supersededTransaction = state.active ? settleDockTransaction(
3069
- state.active,
3070
- { reason: DOCK_TRANSACTION_REASON.SUPERSEDED },
3071
- DOCK_TRANSACTION_STATUS.CANCELLED
3072
- ) : state.last;
3073
- return { active: nextTransaction, last: supersededTransaction };
3074
- }
3075
- const newStatus = action ? TRANSACTION_STATUS_MAP[action.type] : void 0;
3076
- if (newStatus && action && state.active && state.active.id === action.id) {
3077
- return {
3078
- active: null,
3079
- last: settleDockTransaction(state.active, action, newStatus)
3080
- };
3081
- }
3082
- return state;
3083
- }
3084
- function useDockTransactions({
3085
- onTransactionEvent = null,
3086
- onTimeout = null,
3087
- timeoutMs = DOCK_TRANSACTION_TIMEOUT_MS
3088
- } = {}) {
3089
- const [state, dispatch] = useReducer(
3090
- dockTransactionReducer,
3091
- void 0,
3092
- createDockTransactionState
3093
- );
3094
- const activeTransactionRef = useRef(null);
3095
- const nextTransactionIdRef = useRef(0);
3096
- const timeoutRef = useRef(null);
3097
- const onTimeoutRef = useRef(onTimeout);
3098
- const onTransactionEventRef = useRef(onTransactionEvent);
3099
- useEffect(() => {
3100
- onTimeoutRef.current = onTimeout;
3101
- }, [onTimeout]);
3102
- useEffect(() => {
3103
- onTransactionEventRef.current = onTransactionEvent;
3104
- }, [onTransactionEvent]);
3105
- const clearTransactionTimeout = useCallback(() => {
3106
- if (timeoutRef.current !== null) {
3107
- clearTimeout(timeoutRef.current);
3108
- timeoutRef.current = null;
3109
- }
3110
- }, []);
3111
- const settleTransaction = useCallback(
3112
- (id, type, details = {}) => {
3113
- const activeTransaction = activeTransactionRef.current;
3114
- if (!activeTransaction || activeTransaction.id !== id) return false;
3115
- clearTransactionTimeout();
3116
- activeTransactionRef.current = null;
3117
- const event = { ...details, endedAt: Date.now(), id, type };
3118
- const settledTransaction = settleDockTransaction(
3119
- activeTransaction,
3120
- event,
3121
- TRANSACTION_STATUS_MAP[type] || DOCK_TRANSACTION_STATUS.TIMED_OUT
3122
- );
3123
- dispatch(event);
3124
- onTransactionEventRef.current?.({
3125
- transaction: settledTransaction,
3126
- type
3127
- });
3128
- return true;
3129
- },
3130
- [clearTransactionTimeout]
3131
- );
3132
- const beginTransaction = useCallback(
3133
- ({
3134
- from,
3135
- source,
3136
- to
3137
- } = {}) => {
3138
- const activeTransaction = activeTransactionRef.current;
3139
- if (activeTransaction) {
3140
- settleTransaction(
3141
- activeTransaction.id,
3142
- DOCK_TRANSACTION_EVENTS.CANCEL,
3143
- { reason: DOCK_TRANSACTION_REASON.SUPERSEDED }
3144
- );
3145
- }
3146
- const transaction = createDockTransaction({
3147
- from,
3148
- id: ++nextTransactionIdRef.current,
3149
- source,
3150
- to
3151
- });
3152
- activeTransactionRef.current = transaction;
3153
- dispatch({ transaction, type: DOCK_TRANSACTION_EVENTS.START });
3154
- onTransactionEventRef.current?.({
3155
- transaction,
3156
- type: DOCK_TRANSACTION_EVENTS.START
3157
- });
3158
- const safeTimeout = Number(timeoutMs);
3159
- if (Number.isFinite(safeTimeout) && safeTimeout > 0) {
3160
- timeoutRef.current = setTimeout(() => {
3161
- if (!settleTransaction(
3162
- transaction.id,
3163
- DOCK_TRANSACTION_EVENTS.TIME_OUT,
3164
- { reason: DOCK_TRANSACTION_REASON.TIME_OUT }
3165
- ))
3166
- return;
3167
- onTimeoutRef.current?.(transaction);
3168
- }, safeTimeout);
3169
- }
3170
- return transaction;
3171
- },
3172
- [settleTransaction, timeoutMs]
3173
- );
3174
- const completeTransaction = useCallback(
3175
- (id) => settleTransaction(id, DOCK_TRANSACTION_EVENTS.COMPLETE),
3176
- [settleTransaction]
3177
- );
3178
- const cancelTransaction = useCallback(
3179
- (id, reason = null) => settleTransaction(id, DOCK_TRANSACTION_EVENTS.CANCEL, { reason }),
3180
- [settleTransaction]
3181
- );
3182
- const cancelActiveTransaction = useCallback(
3183
- (reason = null) => activeTransactionRef.current ? cancelTransaction(activeTransactionRef.current.id, reason) : false,
3184
- [cancelTransaction]
3185
- );
3186
- const failTransaction = useCallback(
3187
- (id, error) => settleTransaction(id, DOCK_TRANSACTION_EVENTS.FAIL, { error }),
3188
- [settleTransaction]
3189
- );
3190
- const completeTransactionForPath = useCallback(
3191
- (pathname) => {
3192
- const activeTransaction = activeTransactionRef.current;
3193
- if (!activeTransaction || !isSamePath(activeTransaction.to, pathname))
3194
- return false;
3195
- return completeTransaction(activeTransaction.id);
3196
- },
3197
- [completeTransaction]
3198
- );
3199
- const isTransactionCurrent = useCallback(
3200
- (id) => activeTransactionRef.current?.id === id,
3201
- []
3202
- );
3203
- useEffect(() => {
3204
- return () => {
3205
- clearTransactionTimeout();
3206
- activeTransactionRef.current = null;
3207
- };
3208
- }, [clearTransactionTimeout]);
3209
- return useMemo(
3210
- () => ({
3211
- activeTransaction: state.active,
3212
- beginTransaction,
3213
- cancelActiveTransaction,
3214
- cancelTransaction,
3215
- completeTransaction,
3216
- completeTransactionForPath,
3217
- failTransaction,
3218
- isTransactionCurrent,
3219
- lastTransaction: state.last
3220
- }),
3221
- [
3222
- state.active,
3223
- state.last,
3224
- beginTransaction,
3225
- cancelActiveTransaction,
3226
- cancelTransaction,
3227
- completeTransaction,
3228
- completeTransactionForPath,
3229
- failTransaction,
3230
- isTransactionCurrent
3231
- ]
3232
- );
3233
- }
3234
3012
 
3235
3013
  // src/modules/dock/routing/navigation.ts
3236
3014
  function getRoutePolicyOverrides(item) {
@@ -3305,7 +3083,8 @@ function createDockTopology(items = [], { pathname = "" } = {}) {
3305
3083
  };
3306
3084
  }
3307
3085
  function useRoutePrefetch(router, {
3308
- intentDelayMs = DOCK_PREFETCH_INTENT_DELAY_MS
3086
+ intentDelayMs = DOCK_PREFETCH_INTENT_DELAY_MS,
3087
+ navigator: navigator2 = null
3309
3088
  } = {}) {
3310
3089
  const routeStatesRef = useRef(/* @__PURE__ */ new Map());
3311
3090
  const cancelRoutePrefetch = useCallback((href) => {
@@ -3317,7 +3096,7 @@ function useRoutePrefetch(router, {
3317
3096
  }, []);
3318
3097
  const prefetchRoute = useCallback(
3319
3098
  (href, { immediate = false } = {}) => {
3320
- if (!isSafeInternalHref(href) || typeof router?.prefetch !== "function")
3099
+ if (!isSafeInternalHref(href) || !navigator2 && typeof router?.prefetch !== "function")
3321
3100
  return false;
3322
3101
  const routeState = routeStatesRef.current.get(href);
3323
3102
  if (routeState?.isPrefetched || routeState?.timeoutId != null)
@@ -3326,6 +3105,11 @@ function useRoutePrefetch(router, {
3326
3105
  const currentState = routeStatesRef.current.get(href);
3327
3106
  if (!currentState) return;
3328
3107
  currentState.timeoutId = null;
3108
+ if (navigator2) {
3109
+ routeStatesRef.current.delete(href);
3110
+ navigator2.prefetch(href);
3111
+ return;
3112
+ }
3329
3113
  currentState.isPrefetched = true;
3330
3114
  try {
3331
3115
  router.prefetch(href, {
@@ -3352,7 +3136,7 @@ function useRoutePrefetch(router, {
3352
3136
  else nextState.timeoutId = setTimeout(startPrefetch, delay);
3353
3137
  return true;
3354
3138
  },
3355
- [intentDelayMs, router]
3139
+ [intentDelayMs, navigator2, router]
3356
3140
  );
3357
3141
  useEffect(() => {
3358
3142
  const routeStates = routeStatesRef.current;
@@ -3430,6 +3214,25 @@ function emitDockEvent(eventType, data = {}) {
3430
3214
  ...data
3431
3215
  });
3432
3216
  }
3217
+ function useDockNavigator(router) {
3218
+ const shared = useModule("navigation");
3219
+ const [own] = useState(
3220
+ () => shared ? null : createNavigator({ router })
3221
+ );
3222
+ useEffect(() => {
3223
+ own?.setRouter(router);
3224
+ }, [own, router]);
3225
+ useEffect(() => own ? () => own.dispose() : void 0, [own]);
3226
+ return useMemo(
3227
+ () => own ?? { ...shared.actions, dispose: () => {
3228
+ }, store: shared.store },
3229
+ [own, shared]
3230
+ );
3231
+ }
3232
+ var selectTrips = (state) => ({
3233
+ active: state.active,
3234
+ last: state.last
3235
+ });
3433
3236
  function useDockNavigation() {
3434
3237
  const pathname = usePathname();
3435
3238
  const { locationKey, syncLocationKey } = useDockLocationKey();
@@ -3446,95 +3249,78 @@ function useDockNavigation() {
3446
3249
  "useDockNavigation",
3447
3250
  "DockProvider"
3448
3251
  );
3252
+ const navigator2 = useDockNavigator(router);
3253
+ const { active: activeTransaction, last: lastTransaction } = useStore(
3254
+ navigator2.store,
3255
+ selectTrips,
3256
+ shallowEqual
3257
+ );
3449
3258
  const previousLocationKeyRef = useRef(locationKey);
3450
- const handleTransactionTimeout = useCallback(() => {
3451
- clearPreparedRouteReset();
3452
- stopLoading();
3453
- }, [clearPreparedRouteReset, stopLoading]);
3454
- const {
3455
- activeTransaction,
3456
- beginTransaction,
3457
- cancelActiveTransaction,
3458
- cancelTransaction,
3459
- completeTransactionForPath,
3460
- failTransaction,
3461
- isTransactionCurrent,
3462
- lastTransaction
3463
- } = useDockTransactions({
3464
- onTimeout: handleTransactionTimeout
3465
- });
3259
+ const settledTripRef = useRef(lastTransaction);
3260
+ useEffect(() => {
3261
+ if (settledTripRef.current === lastTransaction) return;
3262
+ settledTripRef.current = lastTransaction;
3263
+ if (!lastTransaction) return;
3264
+ if (lastTransaction.status === NAVIGATION_STATUS.COMPLETED) {
3265
+ syncLocationKey();
3266
+ } else if (lastTransaction.status === NAVIGATION_STATUS.TIMED_OUT || lastTransaction.status === NAVIGATION_STATUS.FAILED) {
3267
+ clearPreparedRouteReset();
3268
+ stopLoading();
3269
+ }
3270
+ }, [clearPreparedRouteReset, lastTransaction, stopLoading, syncLocationKey]);
3466
3271
  const cancelDock = useCallback(
3467
3272
  (reason = "guard") => {
3468
- cancelActiveTransaction(reason);
3273
+ navigator2.cancel(reason);
3469
3274
  clearPreparedRouteReset();
3470
3275
  closeSurface({ cancelled: true, reason, success: false });
3471
3276
  },
3472
- [cancelActiveTransaction, clearPreparedRouteReset, closeSurface]
3277
+ [clearPreparedRouteReset, closeSurface, navigator2]
3473
3278
  );
3474
3279
  const commitDock = useCallback(
3475
- ({
3280
+ async ({
3281
+ force = false,
3476
3282
  from,
3477
3283
  href,
3284
+ item,
3478
3285
  routePolicy,
3479
- source = "dock",
3480
- transaction = null
3286
+ source = "dock"
3481
3287
  }) => {
3482
- const activeRouteTransaction = transaction || beginTransaction({ from, source, to: href });
3483
- if (!isTransactionCurrent(activeRouteTransaction.id)) return false;
3484
- try {
3485
- continuity?.remember?.(from);
3288
+ const result = await navigator2.navigate(href, {
3289
+ force,
3290
+ guard: guards.count() > 0 ? () => guards.check(href, from) : void 0,
3291
+ onCommit: () => {
3292
+ continuity?.remember?.(from);
3293
+ blurActiveElement();
3294
+ prepareRouteReset(routePolicy);
3295
+ emitDockEvent(DOCK_EVENTS.NAVIGATE_START, { from, to: href });
3296
+ },
3297
+ source
3298
+ });
3299
+ if (result.ok) {
3300
+ emitDockEvent(DOCK_EVENTS.NAVIGATE, { from, item, to: href });
3301
+ return true;
3302
+ }
3303
+ if (result.blocked) {
3486
3304
  blurActiveElement();
3487
- prepareRouteReset(routePolicy);
3488
- emitDockEvent(DOCK_EVENTS.NAVIGATE_START, { from, to: href });
3489
- router.push(href);
3490
- emitDockEvent(DOCK_EVENTS.NAVIGATE, {
3305
+ openDockGuardConfirmation({
3306
+ closeSurface,
3307
+ commit: (confirmed) => void commitDock({ ...confirmed, force: true }).catch(
3308
+ (error) => report("Dock route transition", error)
3309
+ ),
3491
3310
  from,
3492
- item: void 0,
3493
- to: href
3311
+ href,
3312
+ message: result.blocked.message,
3313
+ routePolicy
3494
3314
  });
3495
- if (typeof window !== "undefined") {
3496
- const currentUrl = new URL(window.location.href);
3497
- const destinationUrl = new URL(href, window.location.origin);
3498
- if (normalizePath(currentUrl.pathname) === normalizePath(destinationUrl.pathname)) {
3499
- window.requestAnimationFrame(() => {
3500
- const currentLocKey = getDockLocationKey({
3501
- hash: window.location.hash,
3502
- pathname: window.location.pathname,
3503
- search: window.location.search
3504
- });
3505
- if (!isSamePath(currentLocKey, href) || !completeTransactionForPath(currentLocKey))
3506
- return;
3507
- emitDockEvent(DOCK_EVENTS.NAVIGATE_END, {
3508
- duration: void 0,
3509
- from,
3510
- to: currentLocKey
3511
- });
3512
- previousLocationKeyRef.current = currentLocKey;
3513
- syncLocationKey();
3514
- stopLoading();
3515
- });
3516
- }
3517
- }
3518
- return true;
3519
- } catch (error) {
3520
- clearPreparedRouteReset();
3521
- failTransaction(activeRouteTransaction.id, error);
3522
- stopLoading();
3523
- report("Dock route transition", error);
3524
- return false;
3525
3315
  }
3316
+ return false;
3526
3317
  },
3527
3318
  [
3528
- beginTransaction,
3529
- clearPreparedRouteReset,
3530
- completeTransactionForPath,
3319
+ closeSurface,
3531
3320
  continuity,
3532
- failTransaction,
3533
- isTransactionCurrent,
3534
- prepareRouteReset,
3535
- router,
3536
- stopLoading,
3537
- syncLocationKey
3321
+ guards,
3322
+ navigator2,
3323
+ prepareRouteReset
3538
3324
  ]
3539
3325
  );
3540
3326
  const navigate = useCallback(
@@ -3550,62 +3336,27 @@ function useDockNavigation() {
3550
3336
  return false;
3551
3337
  }
3552
3338
  if (isSamePath(href, from)) return false;
3553
- const transaction = beginTransaction({ from, source, to: href });
3554
3339
  try {
3555
- if (!force && guards.count() > 0) {
3556
- const guardResult = await guards.check(href, from);
3557
- if (!isTransactionCurrent(transaction.id)) return false;
3558
- if (guardResult.blocked) {
3559
- cancelTransaction(transaction.id, "guard");
3560
- blurActiveElement();
3561
- openDockGuardConfirmation({
3562
- closeSurface,
3563
- commit: commitDock,
3564
- from,
3565
- href,
3566
- message: guardResult.message,
3567
- routePolicy
3568
- });
3569
- return false;
3570
- }
3571
- }
3572
- return commitDock({
3573
- from,
3574
- href,
3575
- routePolicy,
3576
- source,
3577
- transaction
3578
- });
3340
+ return await commitDock({ force, from, href, routePolicy, source });
3579
3341
  } catch (error) {
3580
- failTransaction(transaction.id, error);
3581
3342
  stopLoading();
3582
- report("Dock navigation guard", error);
3343
+ report("Dock navigation", error);
3583
3344
  return false;
3584
3345
  }
3585
3346
  },
3586
- [
3587
- guards,
3588
- beginTransaction,
3589
- cancelTransaction,
3590
- commitDock,
3591
- failTransaction,
3592
- isTransactionCurrent,
3593
- closeSurface,
3594
- locationKey,
3595
- stopLoading
3596
- ]
3347
+ [commitDock, locationKey, stopLoading]
3597
3348
  );
3598
3349
  useEffect(() => {
3350
+ navigator2.arrive(locationKey);
3599
3351
  if (previousLocationKeyRef.current === locationKey) return;
3600
3352
  emitDockEvent(DOCK_EVENTS.NAVIGATE_END, {
3601
3353
  duration: void 0,
3602
3354
  from: previousLocationKeyRef.current,
3603
3355
  to: locationKey
3604
3356
  });
3605
- completeTransactionForPath(locationKey);
3606
3357
  previousLocationKeyRef.current = locationKey;
3607
3358
  stopLoading();
3608
- }, [completeTransactionForPath, locationKey, stopLoading]);
3359
+ }, [locationKey, navigator2, stopLoading]);
3609
3360
  return {
3610
3361
  activeTransaction,
3611
3362
  cancelDock,
@@ -3902,7 +3653,10 @@ function useDockCardItemModel({
3902
3653
  const [isHovered, setIsHovered] = useState(false);
3903
3654
  const pathname = usePathname();
3904
3655
  const router = useRouter();
3905
- const { cancelRoutePrefetch, prefetchRoute } = useRoutePrefetch(router);
3656
+ const navigation = useModule("navigation");
3657
+ const { cancelRoutePrefetch, prefetchRoute } = useRoutePrefetch(router, {
3658
+ navigator: navigation?.actions
3659
+ });
3906
3660
  const hasMedia = useDockHasMedia();
3907
3661
  const isTopHudActive = Boolean(isTop && isHudActive);
3908
3662
  const isCurrentActive = Boolean(
@@ -6053,27 +5807,31 @@ function buildDockItems({
6053
5807
  return filterDockItems(flattenedItems, searchQuery);
6054
5808
  return flattenedItems;
6055
5809
  }
6056
- function resolveBaseActiveItem({
5810
+ function resolveBaseActiveItemMatch({
6057
5811
  rawItems,
6058
5812
  dockItems,
6059
5813
  pathname,
6060
5814
  isNotFoundPage
6061
5815
  }) {
6062
5816
  const normalizedPathname = normalizePath(pathname);
5817
+ const matched = (item) => ({
5818
+ item,
5819
+ isFallback: false
5820
+ });
6063
5821
  const selectedDataSource = dockItems.find(
6064
5822
  (item) => item.isDataSource && item.isSelected
6065
5823
  );
6066
- if (selectedDataSource) return selectedDataSource;
5824
+ if (selectedDataSource) return matched(selectedDataSource);
6067
5825
  if (isNotFoundPage)
6068
- return rawItems.find(isNotFoundItem) || rawItems[0] || null;
5826
+ return matched(rawItems.find(isNotFoundItem) || rawItems[0] || null);
6069
5827
  const matchInDock = dockItems.find(
6070
5828
  (item) => isSamePath(item.path, normalizedPathname) || item.targetPath && isSamePath(item.targetPath, normalizedPathname)
6071
5829
  );
6072
- if (matchInDock) return matchInDock;
5830
+ if (matchInDock) return matched(matchInDock);
6073
5831
  const matchInRaw = rawItems.find(
6074
5832
  (item) => isSamePath(item.path, normalizedPathname) || item.targetPath && isSamePath(item.targetPath, normalizedPathname)
6075
5833
  );
6076
- if (matchInRaw) return matchInRaw;
5834
+ if (matchInRaw) return matched(matchInRaw);
6077
5835
  let prefixMatchedRawItem = null;
6078
5836
  let longestPrefixLength = -1;
6079
5837
  for (let i = 0; i < rawItems.length; i++) {
@@ -6084,11 +5842,65 @@ function resolveBaseActiveItem({
6084
5842
  }
6085
5843
  }
6086
5844
  if (prefixMatchedRawItem) {
6087
- return dockItems.find(
5845
+ const item = dockItems.find(
6088
5846
  (entry) => isSamePath(entry?.path, prefixMatchedRawItem?.path) || entry?.name && entry.name === prefixMatchedRawItem?.name
6089
5847
  ) || prefixMatchedRawItem;
5848
+ return {
5849
+ item,
5850
+ isFallback: normalizePath(prefixMatchedRawItem.path) === "/"
5851
+ };
5852
+ }
5853
+ return { item: rawItems[0] || null, isFallback: true };
5854
+ }
5855
+ function selectPendingRouteItem({
5856
+ match,
5857
+ heldItem,
5858
+ pathname,
5859
+ isHolding
5860
+ }) {
5861
+ if (!match.isFallback || !isHolding || !heldItem) return match.item;
5862
+ if (heldItem.path && isSamePath(heldItem.path, pathname)) return match.item;
5863
+ return heldItem;
5864
+ }
5865
+ function usePendingRouteHold(pathname, match, {
5866
+ holdMs = DOCK_PENDING_ROUTE_HOLD_MS,
5867
+ isNavigating = false
5868
+ } = {}) {
5869
+ const normalizedPathname = normalizePath(pathname);
5870
+ const [lastMatched, setLastMatched] = useState(
5871
+ () => match.isFallback ? null : match.item
5872
+ );
5873
+ const [hold, setHold] = useState(() => ({
5874
+ isOpen: false,
5875
+ pathname: normalizedPathname
5876
+ }));
5877
+ if (!match.isFallback && match.item !== lastMatched) {
5878
+ setLastMatched(match.item);
5879
+ }
5880
+ if (hold.pathname !== normalizedPathname) {
5881
+ setHold({ isOpen: true, pathname: normalizedPathname });
6090
5882
  }
6091
- return rawItems[0] || null;
5883
+ useEffect(() => {
5884
+ if (!hold.isOpen || isNavigating) return;
5885
+ const timer = setTimeout(
5886
+ () => setHold(
5887
+ (current) => current.pathname === hold.pathname ? { ...current, isOpen: false } : current
5888
+ ),
5889
+ holdMs
5890
+ );
5891
+ return () => clearTimeout(timer);
5892
+ }, [hold, holdMs, isNavigating]);
5893
+ const selected = selectPendingRouteItem({
5894
+ heldItem: lastMatched,
5895
+ isHolding: hold.isOpen && hold.pathname === normalizedPathname,
5896
+ match,
5897
+ pathname: normalizedPathname
5898
+ });
5899
+ const isHeld = selected !== match.item;
5900
+ return useMemo(
5901
+ () => isHeld && selected ? { ...selected, isRoutePending: true } : selected,
5902
+ [isHeld, selected]
5903
+ );
6092
5904
  }
6093
5905
  function resolveActiveItem({
6094
5906
  rawItems,
@@ -6103,14 +5915,15 @@ function resolveActiveItem({
6103
5915
  actionStackClass,
6104
5916
  surfaceActions,
6105
5917
  isPageLoading,
6106
- attention
5918
+ attention,
5919
+ baseActiveItem: resolvedBaseActiveItem
6107
5920
  }) {
6108
- const baseActiveItem = resolveBaseActiveItem({
5921
+ const baseActiveItem = resolvedBaseActiveItem !== void 0 ? resolvedBaseActiveItem : resolveBaseActiveItemMatch({
6109
5922
  rawItems,
6110
5923
  dockItems,
6111
5924
  pathname,
6112
5925
  isNotFoundPage
6113
- });
5926
+ }).item;
6114
5927
  if (!baseActiveItem) return null;
6115
5928
  if (attention?.kind === DOCK_ATTENTION_KIND.SURFACE)
6116
5929
  return applySurfaceToDockItem(
@@ -6162,7 +5975,7 @@ function useDockItems() {
6162
5975
  );
6163
5976
  return { rawItems };
6164
5977
  }
6165
- function useDockDisplay(overridePathname) {
5978
+ function useDockDisplay(overridePathname, { isNavigating = false } = {}) {
6166
5979
  const routerPathname = usePathname();
6167
5980
  const pathname = overridePathname || routerPathname;
6168
5981
  const loadingState = useDockLoadingState();
@@ -6242,8 +6055,21 @@ function useDockDisplay(overridePathname) {
6242
6055
  () => buildDockItems({ rawItems, expanded, searchQuery, isNotFoundPage }),
6243
6056
  [rawItems, expanded, searchQuery, isNotFoundPage]
6244
6057
  );
6058
+ const baseMatch = useMemo(
6059
+ () => resolveBaseActiveItemMatch({
6060
+ rawItems,
6061
+ dockItems,
6062
+ pathname,
6063
+ isNotFoundPage
6064
+ }),
6065
+ [rawItems, dockItems, pathname, isNotFoundPage]
6066
+ );
6067
+ const baseActiveItem = usePendingRouteHold(pathname, baseMatch, {
6068
+ isNavigating
6069
+ });
6245
6070
  const activeItem = useMemo(
6246
6071
  () => resolveActiveItem({
6072
+ baseActiveItem,
6247
6073
  rawItems,
6248
6074
  dockItems,
6249
6075
  pathname,
@@ -6268,6 +6094,7 @@ function useDockDisplay(overridePathname) {
6268
6094
  attention
6269
6095
  }),
6270
6096
  [
6097
+ baseActiveItem,
6271
6098
  rawItems,
6272
6099
  dockItems,
6273
6100
  pathname,
@@ -6320,8 +6147,15 @@ function useDockLayout({
6320
6147
  const routePathname = usePathname();
6321
6148
  const pathname = overridePathname || routePathname;
6322
6149
  const { displayItems, displayActiveIndex } = useMemo(() => {
6323
- const items = dockItems || [];
6324
- const activeIndex = findDockItemIndex(items, activeItem ?? null, pathname);
6150
+ const registeredItems = dockItems || [];
6151
+ const registeredIndex = findDockItemIndex(
6152
+ registeredItems,
6153
+ activeItem ?? null,
6154
+ pathname
6155
+ );
6156
+ const isHeldOutsideStack = registeredIndex === -1 && Boolean(activeItem?.isRoutePending);
6157
+ const items = isHeldOutsideStack ? [activeItem, ...registeredItems] : registeredItems;
6158
+ const activeIndex = isHeldOutsideStack ? 0 : registeredIndex;
6325
6159
  const itemsWithActiveItem = replaceActiveItem(
6326
6160
  items,
6327
6161
  activeIndex,
@@ -6376,7 +6210,9 @@ function useDock() {
6376
6210
  pathname
6377
6211
  } = core;
6378
6212
  const effectivePathname = activeTransaction?.to ? normalizePath(activeTransaction.to) : pathname;
6379
- const display = useDockDisplay(effectivePathname);
6213
+ const display = useDockDisplay(effectivePathname, {
6214
+ isNavigating: Boolean(activeTransaction)
6215
+ });
6380
6216
  const { dockItems, activeItem, statusState, attention, topology } = display;
6381
6217
  const isHudModeActive = attention?.kind === DOCK_ATTENTION_KIND.HUD || attention?.kind === DOCK_ATTENTION_KIND.OPERATION;
6382
6218
  const isSurfaceActive = Boolean(activeItem?.isSurface);
@@ -9885,7 +9721,7 @@ var dockModule = defineModule({
9885
9721
  context: DockContext,
9886
9722
  Provider: DockModuleProvider,
9887
9723
  Overlay: Dock,
9888
- uses: ["loading", "media", "notification"],
9724
+ uses: ["loading", "media", "navigation", "notification"],
9889
9725
  registry: {
9890
9726
  cleanupDelayMs: 600,
9891
9727
  keyPolicy: "path",
@@ -9901,5 +9737,5 @@ var dockModule = defineModule({
9901
9737
  });
9902
9738
 
9903
9739
  export { DOCK_EVENTS, DOCK_HUD_PRIORITY, DOCK_HUD_RENDER_MODE, DOCK_HUD_VARIANT, Dock, DockCardBanner, DockCardHeader, DockDescription, DockIcon, DockProvider, DockSurfaceAction, DockSurfaceExtension, DockSurfaceHeaderButton, DockTitle, ErrorActions, GuardActions, createDockGuardRegistry, createErrorStatus, createGuardStatus, createInlineSurfaceEntry, createSurfaceEntryDefinition, createSurfaceFlowBuilder, defineBreadcrumb, defineDockAction, defineHud, defineStepSurface, defineSurface, dockModule, dockTheme, isValidBannerUrl, useDock, useDockActionClass, useDockActions, useDockBanner, useDockConfig, useDockContextActions, useDockDimensions, useDockGuard, useDockHeight, useDockHud, useDockMotion, useDockRegistration, useDockSelector, useDockState, useDockTheme, useHud, useOptionalDockActions, useOptionalDockState, useSurface, useSurfaceAction, useSurfaceDimensions, useSurfaceFlow, useSurfaceHeader, useSurfaceId, useSurfaceReturn, useSurfaceStep };
9904
- //# sourceMappingURL=chunk-A5RE3F6O.js.map
9905
- //# sourceMappingURL=chunk-A5RE3F6O.js.map
9740
+ //# sourceMappingURL=chunk-JIXBFFRD.js.map
9741
+ //# sourceMappingURL=chunk-JIXBFFRD.js.map