hono-preact 0.5.0 → 0.5.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.
@@ -255,33 +255,44 @@ function queryVtNamedElements() {
255
255
  return [];
256
256
  return Array.from(document.querySelectorAll('[style*="view-transition-name"]'));
257
257
  }
258
- // The view-transition-names currently applied in the document (inline styles).
259
- function collectVtNames() {
260
- const names = new Set();
258
+ // The view-transition-names currently applied in the document, mapped to the
259
+ // element carrying each (first wins on the off-chance a name is duplicated).
260
+ // Element identity is what lets the grace tell a persistent name (still on its
261
+ // original node) from a freshly-materialised morph endpoint (see below).
262
+ function collectVtNameElements() {
263
+ const map = new Map();
261
264
  for (const el of queryVtNamedElements()) {
262
265
  const n = el.style?.getPropertyValue?.('view-transition-name');
263
- if (n)
264
- names.add(n);
266
+ if (n && !map.has(n))
267
+ map.set(n, el);
265
268
  }
266
- return names;
269
+ return map;
267
270
  }
268
- // Whether any currently-applied view-transition-name was also in `oldNames`
269
- // i.e. a morph pair (same name old + new) is present.
270
- function hasMorphPartner(oldNames) {
271
- if (oldNames.size === 0)
271
+ // Whether a name from the outgoing route now appears on a DIFFERENT (or new)
272
+ // element than it did before the swap i.e. a genuine destination morph
273
+ // endpoint has materialised. A name still carried by its ORIGINAL element is
274
+ // persistent chrome (e.g. a parent layout's title that doesn't unmount across
275
+ // the nav). Such a name pairs trivially on its own and must NOT satisfy the
276
+ // grace: if it did, the grace would be skipped while the real data-loaded
277
+ // partner (which loads behind inner Suspense, so it doesn't move loadingDepth)
278
+ // is still pending, and the new snapshot would be captured without it.
279
+ function hasFreshMorphPartner(oldNamed) {
280
+ if (oldNamed.size === 0)
272
281
  return false;
273
282
  for (const el of queryVtNamedElements()) {
274
283
  const n = el.style?.getPropertyValue?.('view-transition-name');
275
- if (n && oldNames.has(n))
284
+ if (n && oldNamed.has(n) && oldNamed.get(n) !== el)
276
285
  return true;
277
286
  }
278
287
  return false;
279
288
  }
280
289
  function runNavTransition(process, start) {
281
290
  const from = lastPath;
282
- // The names present in the outgoing route used to know when a morph partner
283
- // has appeared in the new route (see the grace wait below).
284
- const oldNames = collectVtNames();
291
+ // The named elements present in the outgoing route, keyed by name. Used to
292
+ // know when a morph partner has freshly appeared in the new route (see the
293
+ // grace wait below) — element identity distinguishes a persistent name (same
294
+ // node) from a destination endpoint that re-claims the name on a new node.
295
+ const oldNamed = collectVtNameElements();
285
296
  const myGen = ++navGen;
286
297
  transitionActive = true;
287
298
  let transition;
@@ -312,12 +323,15 @@ function runNavTransition(process, start) {
312
323
  break; // timed out waiting
313
324
  contentProcess();
314
325
  }
315
- // If the outgoing route had named elements but none has a partner in the
316
- // new shell yet, the partner may load with the route's DATA (behind
317
- // inner Suspense, which doesn't move loadingDepth — e.g. a list whose
318
- // items come from a loader). Wait briefly for it so the morph can pair.
319
- if (oldNames.size > 0 && !hasMorphPartner(oldNames)) {
320
- while (!hasMorphPartner(oldNames)) {
326
+ // If the outgoing route had named elements but none has a FRESH partner
327
+ // in the new shell yet, the partner may load with the route's DATA
328
+ // (behind inner Suspense, which doesn't move loadingDepth — e.g. a list
329
+ // whose items come from a loader). Wait briefly for it so the morph can
330
+ // pair. "Fresh" ignores names that merely persisted on their original
331
+ // element (parent-layout chrome); otherwise such a name would satisfy
332
+ // the check immediately and the real partner would never be awaited.
333
+ if (oldNamed.size > 0 && !hasFreshMorphPartner(oldNamed)) {
334
+ while (!hasFreshMorphPartner(oldNamed)) {
321
335
  const contentProcess = await waitForColdFlush(myGen, MORPH_PARTNER_GRACE_MS);
322
336
  if (navGen !== myGen)
323
337
  return;
@@ -0,0 +1,5 @@
1
+ export declare class TimeoutError extends Error {
2
+ readonly kind: "timeout";
3
+ readonly timeoutMs: number;
4
+ constructor(timeoutMs: number);
5
+ }
@@ -0,0 +1,9 @@
1
+ export class TimeoutError extends Error {
2
+ kind = 'timeout';
3
+ timeoutMs;
4
+ constructor(timeoutMs) {
5
+ super(`Request timed out after ${timeoutMs}ms`);
6
+ this.name = 'TimeoutError';
7
+ this.timeoutMs = timeoutMs;
8
+ }
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono-preact",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Hono on the edge, Preact in the browser, manifest driven routes, typed RPC, streaming everywhere.",
5
5
  "keywords": [
6
6
  "hono",
@@ -95,10 +95,11 @@
95
95
  },
96
96
  "devDependencies": {
97
97
  "typescript": "*",
98
- "@hono-preact/iso": "0.1.0",
99
98
  "@hono-preact/server": "0.1.0",
99
+ "@hono-preact/iso": "0.1.0",
100
100
  "@hono-preact/vite": "0.1.0"
101
101
  },
102
+ "sideEffects": false,
102
103
  "scripts": {
103
104
  "build": "tsc && node scripts/consolidate.mjs",
104
105
  "dev": "tsc --watch"