@xingwangzhe/stalux 1.40.0 → 1.40.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/README.md CHANGED
@@ -18,7 +18,7 @@ Standalone images written as `![Image description](url)` receive a `figure` and
18
18
 
19
19
  Code blocks default to the single `dark-plus` theme, with system color-scheme switching and theme selectors disabled. To opt into another theme or switching behavior, explicitly override `themes`, `useDarkModeMediaQuery`, and `themeCssSelector` through `expressiveCode`. This only changes generated code styles and adds no telemetry.
20
20
 
21
- Route changes use native CSS View Transitions for one visible semantic heading in the incoming page. The policy covers every theme route category: normal effects take 100–180ms, with short 100–120ms fades on mobile. Entering an article, returning to a list, filtering categories or tags, explicit previous/next article controls, and returning home receive hints that follow reading intent. History traversal restores the existing scroll position; offscreen headings remain out of view. Reduced motion, browser-provided history gestures and same-page anchors add no visible VT animation. Standalone HTML keeps native navigation. See the [1.40.0 transition policy](https://github.com/xingwangzhe/stalux/blob/v1.40.0/docs/view-transitions-1.40.0.md).
21
+ Route changes use native CSS View Transitions for one visible semantic heading in the incoming page. The policy covers every theme route category: normal effects take 100–180ms, with short 100–120ms fades on mobile. Entering an article, returning to a list, filtering categories or tags, explicit previous/next article controls, and returning home receive hints that follow reading intent. History traversal restores the existing scroll position; offscreen headings remain out of view. Reduced motion, browser-provided history gestures and same-page anchors add no visible VT animation. Standalone HTML keeps native navigation. See the [1.40.0 transition policy](https://github.com/xingwangzhe/stalux/blob/v1.40.1/docs/view-transitions-1.40.1.md).
22
22
 
23
23
  The sticky header stays at the top while the body grows with long content; the persisted header and footer stay in place during navigation. Text is immediately clear, and the incoming heading is measured once after Astro swaps the document and restores scrolling. Astro continues to own document/font preparation, history, scrolling and page-script lifecycle. Shared motion state settles when the native transition finishes or is canceled. CSS animation duration is reported separately from total navigation time, which includes networking, layout and browser settlement.
24
24
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xingwangzhe/stalux",
3
- "version": "1.40.0",
3
+ "version": "1.40.1",
4
4
  "description": "A powerful, modern Astro blog theme — use as template or install as plugin",
5
5
  "keywords": [
6
6
  "astro",
@@ -94,15 +94,19 @@ function preserveHeaderMetrics(nextDocument: Document): void {
94
94
  const transitionWindow = window as TransitionWindow;
95
95
  if (!transitionWindow.__STALUX_VT_LISTENER__) {
96
96
  transitionWindow.__STALUX_VT_LISTENER__ = true;
97
+ let pendingNavigation = 0;
98
+ let swappedNavigation = 0;
97
99
 
98
100
  // A current-page link is not a page replacement. Intercept before Astro's
99
101
  // delegated handler, but keep propagation for menu cleanup and click tracking.
102
+ // During preparation, Astro must receive it to cancel an incoming route.
100
103
  // Hash changes, explicit reloads, downloads and modified/new-tab clicks keep
101
104
  // their native behavior.
102
105
  document.addEventListener(
103
106
  "click",
104
107
  (event) => {
105
108
  if (
109
+ pendingNavigation !== 0 ||
106
110
  event.defaultPrevented ||
107
111
  event.button !== 0 ||
108
112
  event.metaKey ||
@@ -148,6 +152,12 @@ if (!transitionWindow.__STALUX_VT_LISTENER__) {
148
152
  document.addEventListener("astro:before-preparation", (event) => {
149
153
  const navigation = event as unknown as NavigationEvent;
150
154
  const current = ++generation;
155
+ pendingNavigation = current;
156
+ const cancelPreparation = () => {
157
+ if (current !== generation) return;
158
+ pendingNavigation = 0;
159
+ clearNavigationState();
160
+ };
151
161
  motion?.cancel();
152
162
  // Only the incoming heading animates. Drop any prior marker without
153
163
  // measuring/capturing a hidden outgoing title or flushing its layout.
@@ -166,25 +176,21 @@ if (!transitionWindow.__STALUX_VT_LISTENER__) {
166
176
  });
167
177
  pendingBrowserMotion = false;
168
178
  setNavigationState(navigation, preset);
169
- navigation.signal.addEventListener(
170
- "abort",
171
- () => {
172
- if (current === generation) clearNavigationState();
173
- },
174
- { once: true },
175
- );
179
+ navigation.signal.addEventListener("abort", cancelPreparation, { once: true });
180
+ if (navigation.signal.aborted) cancelPreparation();
176
181
  queueMicrotask(() => {
177
- if (event.defaultPrevented && current === generation) clearNavigationState();
182
+ if (event.defaultPrevented) cancelPreparation();
178
183
  });
179
184
  const loader = navigation.loader;
180
185
  navigation.loader = async () => {
181
186
  try {
182
187
  await loader();
183
- if (!event.defaultPrevented) {
188
+ if (event.defaultPrevented) cancelPreparation();
189
+ else {
184
190
  await prepareNavigationFont(navigation.newDocument, navigation.signal);
185
191
  }
186
192
  } catch (error) {
187
- if (current === generation) clearNavigationState();
193
+ cancelPreparation();
188
194
  throw error;
189
195
  }
190
196
  };
@@ -194,6 +200,7 @@ if (!transitionWindow.__STALUX_VT_LISTENER__) {
194
200
  const navigation = event as unknown as NavigationEvent;
195
201
  if (navigation.signal.aborted) return;
196
202
  const current = generation;
203
+ swappedNavigation = current;
197
204
  preserveHeaderMetrics(navigation.newDocument);
198
205
  // Astro replaces the root attributes during swap. Carry state into the
199
206
  // new document; CSS keyframes read these data-* attributes to pick their
@@ -219,6 +226,8 @@ if (!transitionWindow.__STALUX_VT_LISTENER__) {
219
226
  });
220
227
 
221
228
  document.addEventListener("astro:page-load", () => {
229
+ // A previous route's scripts can finish while a newer loader is pending.
230
+ if (swappedNavigation === generation) pendingNavigation = 0;
222
231
  setRouteState(window.location.pathname);
223
232
  });
224
233