@moku-labs/web 2.4.1 → 2.4.2

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/browser.mjs CHANGED
@@ -3867,6 +3867,17 @@ function createSpaKernel(state, config, emit, deps) {
3867
3867
  let pendingScrollToTop = true;
3868
3868
  let pendingTransition = resolveTransition(resolved.defaultTransition);
3869
3869
  let pushingOwnUrl = false;
3870
+ let programmatic;
3871
+ /**
3872
+ * Aborts the programmatic navigation still loading, if any.
3873
+ *
3874
+ * @example
3875
+ * supersedeProgrammatic(); // a link click or back/forward starts
3876
+ */
3877
+ const supersedeProgrammatic = () => {
3878
+ programmatic?.abort();
3879
+ programmatic = void 0;
3880
+ };
3870
3881
  /**
3871
3882
  * Resolve a {@link TransitionMode} into the runtime {@link SwapTransition} the swap
3872
3883
  * consumes: `"none"` ⇒ disabled; `"crossfade"` ⇒ enabled, no named types (default root
@@ -4181,7 +4192,8 @@ function createSpaKernel(state, config, emit, deps) {
4181
4192
  * swaps but the address bar (and the back button / refresh / deep link) stays on the old URL.
4182
4193
  * Where the Navigation API exists, `history.pushState` fires a `navigate` event synchronously
4183
4194
  * (Chrome, Edge, Safari 26): `pushingOwnUrl` marks it, so the interceptor does not run this
4184
- * navigation a second time. The current scroll is saved first so a later back restores it.
4195
+ * navigation a second time. The current scroll is saved first so a later back restores it. It
4196
+ * carries its own abort signal: any later navigation aborts it before it can swap.
4185
4197
  *
4186
4198
  * @param path - The destination path (pathname + optional search).
4187
4199
  * @param scroll - The optional per-call scroll override.
@@ -4199,7 +4211,12 @@ function createSpaKernel(state, config, emit, deps) {
4199
4211
  pushingOwnUrl = false;
4200
4212
  }
4201
4213
  }
4202
- navigate(path, true, void 0, scroll).catch(() => {});
4214
+ supersedeProgrammatic();
4215
+ const controller = new AbortController();
4216
+ programmatic = controller;
4217
+ navigate(path, true, controller.signal, scroll).catch(() => {}).finally(() => {
4218
+ if (programmatic === controller) programmatic = void 0;
4219
+ });
4203
4220
  };
4204
4221
  return {
4205
4222
  /**
@@ -4226,7 +4243,10 @@ function createSpaKernel(state, config, emit, deps) {
4226
4243
  if (state.started) throw new Error(`${ERROR_PREFIX} spa kernel already started.\n Call app.stop() before booting again (single boot per app).`);
4227
4244
  progress = createProgressBar(resolved.progressBar);
4228
4245
  state.currentUrl = currentLocationUrl();
4229
- state.destroyRouter = attachRouter(handlers, navigate, () => pushingOwnUrl);
4246
+ state.destroyRouter = attachRouter(handlers, (pathname, scrollToTop, signal, scrollOverride) => {
4247
+ supersedeProgrammatic();
4248
+ return navigate(pathname, scrollToTop, signal, scrollOverride);
4249
+ }, () => pushingOwnUrl);
4230
4250
  const matchPath = state.currentUrl.split("?")[0] ?? state.currentUrl;
4231
4251
  const hit = deps.router.match(matchPath);
4232
4252
  if (hit?.route._handlers.render && isClientOnlyRoute(deps.router.mode(), hit.route)) bootRender(state.currentUrl);
package/dist/index.cjs CHANGED
@@ -10961,6 +10961,17 @@ function createSpaKernel(state, config, emit, deps) {
10961
10961
  let pendingScrollToTop = true;
10962
10962
  let pendingTransition = resolveTransition(resolved.defaultTransition);
10963
10963
  let pushingOwnUrl = false;
10964
+ let programmatic;
10965
+ /**
10966
+ * Aborts the programmatic navigation still loading, if any.
10967
+ *
10968
+ * @example
10969
+ * supersedeProgrammatic(); // a link click or back/forward starts
10970
+ */
10971
+ const supersedeProgrammatic = () => {
10972
+ programmatic?.abort();
10973
+ programmatic = void 0;
10974
+ };
10964
10975
  /**
10965
10976
  * Resolve a {@link TransitionMode} into the runtime {@link SwapTransition} the swap
10966
10977
  * consumes: `"none"` ⇒ disabled; `"crossfade"` ⇒ enabled, no named types (default root
@@ -11275,7 +11286,8 @@ function createSpaKernel(state, config, emit, deps) {
11275
11286
  * swaps but the address bar (and the back button / refresh / deep link) stays on the old URL.
11276
11287
  * Where the Navigation API exists, `history.pushState` fires a `navigate` event synchronously
11277
11288
  * (Chrome, Edge, Safari 26): `pushingOwnUrl` marks it, so the interceptor does not run this
11278
- * navigation a second time. The current scroll is saved first so a later back restores it.
11289
+ * navigation a second time. The current scroll is saved first so a later back restores it. It
11290
+ * carries its own abort signal: any later navigation aborts it before it can swap.
11279
11291
  *
11280
11292
  * @param path - The destination path (pathname + optional search).
11281
11293
  * @param scroll - The optional per-call scroll override.
@@ -11293,7 +11305,12 @@ function createSpaKernel(state, config, emit, deps) {
11293
11305
  pushingOwnUrl = false;
11294
11306
  }
11295
11307
  }
11296
- navigate(path, true, void 0, scroll).catch(() => {});
11308
+ supersedeProgrammatic();
11309
+ const controller = new AbortController();
11310
+ programmatic = controller;
11311
+ navigate(path, true, controller.signal, scroll).catch(() => {}).finally(() => {
11312
+ if (programmatic === controller) programmatic = void 0;
11313
+ });
11297
11314
  };
11298
11315
  return {
11299
11316
  /**
@@ -11320,7 +11337,10 @@ function createSpaKernel(state, config, emit, deps) {
11320
11337
  if (state.started) throw new Error(`${ERROR_PREFIX} spa kernel already started.\n Call app.stop() before booting again (single boot per app).`);
11321
11338
  progress = createProgressBar(resolved.progressBar);
11322
11339
  state.currentUrl = currentLocationUrl();
11323
- state.destroyRouter = attachRouter(handlers, navigate, () => pushingOwnUrl);
11340
+ state.destroyRouter = attachRouter(handlers, (pathname, scrollToTop, signal, scrollOverride) => {
11341
+ supersedeProgrammatic();
11342
+ return navigate(pathname, scrollToTop, signal, scrollOverride);
11343
+ }, () => pushingOwnUrl);
11324
11344
  const matchPath = state.currentUrl.split("?")[0] ?? state.currentUrl;
11325
11345
  const hit = deps.router.match(matchPath);
11326
11346
  if (hit?.route._handlers.render && isClientOnlyRoute(deps.router.mode(), hit.route)) bootRender(state.currentUrl);
package/dist/index.mjs CHANGED
@@ -10917,6 +10917,17 @@ function createSpaKernel(state, config, emit, deps) {
10917
10917
  let pendingScrollToTop = true;
10918
10918
  let pendingTransition = resolveTransition(resolved.defaultTransition);
10919
10919
  let pushingOwnUrl = false;
10920
+ let programmatic;
10921
+ /**
10922
+ * Aborts the programmatic navigation still loading, if any.
10923
+ *
10924
+ * @example
10925
+ * supersedeProgrammatic(); // a link click or back/forward starts
10926
+ */
10927
+ const supersedeProgrammatic = () => {
10928
+ programmatic?.abort();
10929
+ programmatic = void 0;
10930
+ };
10920
10931
  /**
10921
10932
  * Resolve a {@link TransitionMode} into the runtime {@link SwapTransition} the swap
10922
10933
  * consumes: `"none"` ⇒ disabled; `"crossfade"` ⇒ enabled, no named types (default root
@@ -11231,7 +11242,8 @@ function createSpaKernel(state, config, emit, deps) {
11231
11242
  * swaps but the address bar (and the back button / refresh / deep link) stays on the old URL.
11232
11243
  * Where the Navigation API exists, `history.pushState` fires a `navigate` event synchronously
11233
11244
  * (Chrome, Edge, Safari 26): `pushingOwnUrl` marks it, so the interceptor does not run this
11234
- * navigation a second time. The current scroll is saved first so a later back restores it.
11245
+ * navigation a second time. The current scroll is saved first so a later back restores it. It
11246
+ * carries its own abort signal: any later navigation aborts it before it can swap.
11235
11247
  *
11236
11248
  * @param path - The destination path (pathname + optional search).
11237
11249
  * @param scroll - The optional per-call scroll override.
@@ -11249,7 +11261,12 @@ function createSpaKernel(state, config, emit, deps) {
11249
11261
  pushingOwnUrl = false;
11250
11262
  }
11251
11263
  }
11252
- navigate(path, true, void 0, scroll).catch(() => {});
11264
+ supersedeProgrammatic();
11265
+ const controller = new AbortController();
11266
+ programmatic = controller;
11267
+ navigate(path, true, controller.signal, scroll).catch(() => {}).finally(() => {
11268
+ if (programmatic === controller) programmatic = void 0;
11269
+ });
11253
11270
  };
11254
11271
  return {
11255
11272
  /**
@@ -11276,7 +11293,10 @@ function createSpaKernel(state, config, emit, deps) {
11276
11293
  if (state.started) throw new Error(`${ERROR_PREFIX} spa kernel already started.\n Call app.stop() before booting again (single boot per app).`);
11277
11294
  progress = createProgressBar(resolved.progressBar);
11278
11295
  state.currentUrl = currentLocationUrl();
11279
- state.destroyRouter = attachRouter(handlers, navigate, () => pushingOwnUrl);
11296
+ state.destroyRouter = attachRouter(handlers, (pathname, scrollToTop, signal, scrollOverride) => {
11297
+ supersedeProgrammatic();
11298
+ return navigate(pathname, scrollToTop, signal, scrollOverride);
11299
+ }, () => pushingOwnUrl);
11280
11300
  const matchPath = state.currentUrl.split("?")[0] ?? state.currentUrl;
11281
11301
  const hit = deps.router.match(matchPath);
11282
11302
  if (hit?.route._handlers.render && isClientOnlyRoute(deps.router.mode(), hit.route)) bootRender(state.currentUrl);
package/package.json CHANGED
@@ -137,5 +137,5 @@
137
137
  "release:doctor": "moku-release doctor",
138
138
  "release": "moku-release"
139
139
  },
140
- "version": "2.4.1"
140
+ "version": "2.4.2"
141
141
  }