Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tiling-duplicate-tile-ids.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@embedpdf/plugin-tiling': patch
---

Fix duplicate tile ids emitted by the UPDATE_VISIBLE_TILES reducer when the scale changes while fallback tiles from an earlier generation are still present. Tile ids encode page/scale/rect but not rotation, so rotating 90° → 270° under a fit zoom mode revisits an earlier scale and re-generates identical ids; the scale-change branch concatenated carried and fresh tiles without deduplication. Keyed renderers crash on the duplicates — in Svelte this throws `each_key_duplicate` mid-flush and can wedge the tab.
13 changes: 11 additions & 2 deletions packages/plugin-tiling/src/lib/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,17 @@ export const tilingReducer: Reducer<TilingState, TilingAction> = (state, action)
/* 2️⃣ decide which fallback tiles to keep */
const fallbackToCarry = promoted.length > 0 ? [] : prevTiles.filter((t) => t.isFallback);

/* 3️⃣ final list = (maybe-kept fallback) + promoted + newTiles */
nextPages[pageIndex] = [...fallbackToCarry, ...promoted, ...newTiles];
/* 3️⃣ final list = (maybe-kept fallback) + promoted + newTiles.
Tile ids encode page/scale/rect but not rotation, so a carried
tile can share an id with a new tile (e.g. rotating 90° → 270°
under a fit zoom mode revisits the same scale and rects while
old fallbacks are still alive). Keyed renderers crash on
duplicate ids, so the fresh tile wins. */
const newIds = new Set(newTiles.map((t) => t.id));
nextPages[pageIndex] = [
...[...fallbackToCarry, ...promoted].filter((t) => !newIds.has(t.id)),
...newTiles,
];
} else {
/* same zoom → keep current fallback, replace visible */
const newIds = new Set(newTiles.map((t) => t.id));
Expand Down