@prose-reader/core 1.176.0 → 1.178.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.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { switchMap, of, fromEvent, take, map, from, takeUntil, Observable, defer, Subject, combineLatest, merge, EMPTY, withLatestFrom, BehaviorSubject, filter, share, first as first$1, mergeMap, endWith, tap as tap$1, finalize, catchError, lastValueFrom, NEVER, scheduled, animationFrameScheduler, distinctUntilChanged as distinctUntilChanged$1, throttleTime, debounceTime as debounceTime$1, startWith as startWith$1, switchScan, forkJoin, shareReplay as shareReplay$1, delay, ReplaySubject, identity, timer, skip as skip$1, exhaustMap, reduce, concatMap } from "rxjs";
2
2
  import { switchMap as switchMap$1, first, map as map$1, startWith, shareReplay, distinctUntilChanged, tap, pairwise, take as take$1, takeUntil as takeUntil$1, filter as filter$1, debounceTime, skip, mergeMap as mergeMap$1, catchError as catchError$1, withLatestFrom as withLatestFrom$1, share as share$1 } from "rxjs/operators";
3
- import { shallowMergeIfDefined, isShallowEqual, parseContentType, detectMimeTypeFromName, getParentPath, arrayEqual } from "@prose-reader/shared";
3
+ import { shallowMergeIfDefined, isShallowEqual, getParentPath, parseContentType, detectMimeTypeFromName, arrayEqual } from "@prose-reader/shared";
4
4
  import { isShallowEqual as isShallowEqual2 } from "@prose-reader/shared";
5
5
  const getAttributeValueFromString = (string, key) => {
6
6
  const regExp = new RegExp(`${key}\\s*=\\s*([0-9.]+)`, `i`);
@@ -413,6 +413,51 @@ const isTouchEvent = (event) => {
413
413
  return false;
414
414
  };
415
415
  const noopElement = () => document.createElement("div");
416
+ const getElementsWithAssets = (_document) => {
417
+ const RESOURCE_ELEMENTS = [
418
+ "img",
419
+ // Images
420
+ "video",
421
+ // Video files
422
+ "audio",
423
+ // Audio files
424
+ "source",
425
+ // Source elements within video/audio
426
+ "link",
427
+ // Stylesheets and other linked resources
428
+ "script"
429
+ // JavaScript files
430
+ ].join(",");
431
+ return Array.from((_document == null ? void 0 : _document.querySelectorAll(RESOURCE_ELEMENTS)) || []);
432
+ };
433
+ const revokeDocumentBlobs = (_document) => {
434
+ const elementsWithAsset = getElementsWithAssets(_document);
435
+ elementsWithAsset.forEach((element) => {
436
+ var _a;
437
+ const url = element.getAttribute("src") || element.getAttribute("href");
438
+ if (url == null ? void 0 : url.startsWith("blob:")) {
439
+ (_a = _document == null ? void 0 : _document.defaultView) == null ? void 0 : _a.URL.revokeObjectURL(url);
440
+ }
441
+ });
442
+ if (_document) {
443
+ const styleSheets = Array.from(_document.styleSheets || []);
444
+ for (const sheet of styleSheets) {
445
+ const rules = Array.from(sheet.cssRules || []);
446
+ for (const rule of rules) {
447
+ if (_document.defaultView && rule instanceof _document.defaultView.CSSFontFaceRule) {
448
+ const src = rule.style.getPropertyValue("src");
449
+ const blobUrls = src.match(/blob:[^,\s'")]+/g);
450
+ if (blobUrls) {
451
+ blobUrls.forEach((url) => {
452
+ var _a;
453
+ (_a = _document == null ? void 0 : _document.defaultView) == null ? void 0 : _a.URL.revokeObjectURL(url);
454
+ });
455
+ }
456
+ }
457
+ }
458
+ }
459
+ }
460
+ };
416
461
  const translateFramePositionIntoPage = ({
417
462
  position,
418
463
  frameElement
@@ -1054,31 +1099,169 @@ class DocumentRenderer extends DestroyableClass {
1054
1099
  return ((_a = this.context.manifest) == null ? void 0 : _a.renditionLayout) ?? "reflowable";
1055
1100
  }
1056
1101
  }
1057
- const createFrameElement = Report.measurePerformance(
1058
- `SpineItemFrame createFrame`,
1059
- Infinity,
1060
- () => {
1061
- const frame = document.createElement(`iframe`);
1062
- frame.frameBorder = `no`;
1063
- frame.tabIndex = 0;
1064
- frame.setAttribute(
1065
- `sandbox`,
1066
- `
1067
- allow-same-origin
1068
- allow-scripts
1069
- allow-top-navigation-to-custom-protocols
1070
- `
1102
+ const defaultGetResource = (item) => new URL(item.href);
1103
+ class ResourceHandler {
1104
+ constructor(item, settings) {
1105
+ this.item = item;
1106
+ this.settings = settings;
1107
+ }
1108
+ async getResource() {
1109
+ var _a, _b;
1110
+ const resource = await lastValueFrom(
1111
+ ((_b = (_a = this.settings.values).getResource) == null ? void 0 : _b.call(_a, this.item)) ?? of(void 0)
1071
1112
  );
1072
- frame.style.cssText = `
1073
- overflow: hidden;
1074
- background-color: transparent;
1075
- border: 0px none transparent;
1076
- padding: 0px;
1077
- `;
1078
- frame.setAttribute(`role`, `main`);
1079
- return frame;
1113
+ return resource ?? defaultGetResource(this.item);
1114
+ }
1115
+ async fetchResource() {
1116
+ const resource = await this.getResource();
1117
+ if (resource instanceof Response) return resource;
1118
+ if (resource instanceof URL) return fetch(resource);
1119
+ return resource;
1120
+ }
1121
+ }
1122
+ const joinPath = (base, path) => {
1123
+ const isFileProtocol = base.startsWith("file://");
1124
+ const tempBase = isFileProtocol ? base.replace("file://", "http://") : base;
1125
+ const result = new URL(path, tempBase).toString();
1126
+ return isFileProtocol ? result.replace("http://", "file://") : result;
1127
+ };
1128
+ const loadFontFaces = async (document2, element, spineItemUriParentPath, context, settings) => {
1129
+ if (!document2 || !document2.defaultView) return;
1130
+ const sheet = element.sheet;
1131
+ if (!sheet) return;
1132
+ try {
1133
+ const rules = Array.from(sheet.cssRules || []);
1134
+ for (let i = 0; i < rules.length; i++) {
1135
+ const rule = rules[i];
1136
+ if (document2.defaultView && rule instanceof document2.defaultView.CSSFontFaceRule) {
1137
+ const src = rule.style.getPropertyValue("src");
1138
+ const matches = src.match(/url\(['"]?([^'"]+)['"]?\)/g);
1139
+ if (matches) {
1140
+ const srcParts = src.split(",").map((part) => part.trim());
1141
+ const newSrcParts = await Promise.all(
1142
+ srcParts.map(async (part) => {
1143
+ var _a, _b;
1144
+ if (part.startsWith("local(")) {
1145
+ return part;
1146
+ }
1147
+ const urlMatch = part.match(/url\(['"]?([^'"]+)['"]?\)/);
1148
+ if (!urlMatch) return part;
1149
+ const originalSrc = urlMatch[1] ?? ``;
1150
+ const foundItem = (_a = context.manifest) == null ? void 0 : _a.items.find(({ href }) => {
1151
+ return `${joinPath(spineItemUriParentPath, originalSrc).toLowerCase()}`.endsWith(
1152
+ `${href.toLowerCase()}`
1153
+ );
1154
+ });
1155
+ if (foundItem) {
1156
+ const resourceHandler = new ResourceHandler(foundItem, settings);
1157
+ try {
1158
+ const resource = await resourceHandler.getResource();
1159
+ if (resource instanceof Response) {
1160
+ const blob = await resource.blob();
1161
+ const blobUrl = (_b = document2.defaultView) == null ? void 0 : _b.URL.createObjectURL(blob);
1162
+ const newPart = part.replace(
1163
+ urlMatch[0],
1164
+ `url("${blobUrl}")`
1165
+ );
1166
+ return newPart;
1167
+ }
1168
+ } catch (e) {
1169
+ console.error("Error loading font:", e);
1170
+ }
1171
+ }
1172
+ return part;
1173
+ })
1174
+ );
1175
+ const newRule = rule.cssText.replace(
1176
+ /src:\s*[^;]+;/,
1177
+ `src: ${newSrcParts.join(", ")};`
1178
+ );
1179
+ sheet.deleteRule(i);
1180
+ sheet.insertRule(newRule, i);
1181
+ }
1182
+ }
1183
+ }
1184
+ } catch (e) {
1185
+ console.error("Could not access stylesheet rules:", e);
1080
1186
  }
1187
+ };
1188
+ const loadElementSrc = (_document, element, spineItemUriParentPath, context, settings) => {
1189
+ var _a;
1190
+ const originalSrc = element.getAttribute("src") || element.getAttribute("href");
1191
+ if (!originalSrc) return of(null);
1192
+ const foundItem = (_a = context.manifest) == null ? void 0 : _a.items.find(({ href }) => {
1193
+ return `${joinPath(spineItemUriParentPath, originalSrc).toLowerCase()}`.endsWith(
1194
+ `${href.toLowerCase()}`
1195
+ );
1196
+ });
1197
+ if (!foundItem) return of(null);
1198
+ const resourceHandler = new ResourceHandler(foundItem, settings);
1199
+ return from(resourceHandler.getResource()).pipe(
1200
+ mergeMap(
1201
+ (resource) => resource instanceof Response ? from(resource.blob()) : of(void 0)
1202
+ ),
1203
+ mergeMap((blob) => {
1204
+ var _a2;
1205
+ if (!blob) {
1206
+ return of(null);
1207
+ }
1208
+ const blobUrl = ((_a2 = _document == null ? void 0 : _document.defaultView) == null ? void 0 : _a2.URL.createObjectURL(blob)) ?? ``;
1209
+ if (element.hasAttribute("src")) {
1210
+ element.setAttribute("src", blobUrl);
1211
+ } else if (element.hasAttribute("href")) {
1212
+ element.setAttribute("href", blobUrl);
1213
+ if ((_document == null ? void 0 : _document.defaultView) && element instanceof _document.defaultView.HTMLLinkElement) {
1214
+ return new Observable((observer) => {
1215
+ element.onload = async () => {
1216
+ try {
1217
+ if (element.sheet) {
1218
+ await loadFontFaces(
1219
+ _document,
1220
+ element,
1221
+ spineItemUriParentPath,
1222
+ context,
1223
+ settings
1224
+ );
1225
+ }
1226
+ observer.next();
1227
+ observer.complete();
1228
+ } catch (error) {
1229
+ observer.error(error);
1230
+ }
1231
+ };
1232
+ element.onerror = observer.error;
1233
+ });
1234
+ }
1235
+ }
1236
+ return of(null);
1237
+ })
1238
+ );
1239
+ };
1240
+ const loadAssets = ({
1241
+ settings,
1242
+ item,
1243
+ context
1244
+ }) => (stream) => stream.pipe(
1245
+ switchMap((frameElement) => {
1246
+ const elementsWithAsset = getElementsWithAssets(
1247
+ frameElement.contentDocument
1248
+ );
1249
+ const spineItemUriParentPath = getParentPath(item.href);
1250
+ const assetsLoad$ = elementsWithAsset.map(
1251
+ (element) => loadElementSrc(
1252
+ frameElement.contentDocument,
1253
+ element,
1254
+ spineItemUriParentPath,
1255
+ context,
1256
+ settings
1257
+ )
1258
+ );
1259
+ return combineLatest(assetsLoad$).pipe(map(() => frameElement));
1260
+ })
1081
1261
  );
1262
+ const unloadAssets = (frameElement) => {
1263
+ revokeDocumentBlobs(frameElement == null ? void 0 : frameElement.contentDocument);
1264
+ };
1082
1265
  const getIntrinsicDimensionsFromBase64Img = (data) => new Promise((resolve, reject) => {
1083
1266
  const image = new Image();
1084
1267
  image.src = data;
@@ -1181,6 +1364,31 @@ const attachFrameSrc = ({
1181
1364
  })
1182
1365
  );
1183
1366
  };
1367
+ const createFrameElement = Report.measurePerformance(
1368
+ `SpineItemFrame createFrame`,
1369
+ Infinity,
1370
+ () => {
1371
+ const frame = document.createElement(`iframe`);
1372
+ frame.frameBorder = `no`;
1373
+ frame.tabIndex = 0;
1374
+ frame.setAttribute(
1375
+ `sandbox`,
1376
+ `
1377
+ allow-same-origin
1378
+ allow-scripts
1379
+ allow-top-navigation-to-custom-protocols
1380
+ `
1381
+ );
1382
+ frame.style.cssText = `
1383
+ overflow: hidden;
1384
+ background-color: transparent;
1385
+ border: 0px none transparent;
1386
+ padding: 0px;
1387
+ `;
1388
+ frame.setAttribute(`role`, `main`);
1389
+ return frame;
1390
+ }
1391
+ );
1184
1392
  const getStyleForViewportDocument = () => {
1185
1393
  return `
1186
1394
  body {
@@ -1673,98 +1881,6 @@ const renderReflowable = ({
1673
1881
  latestContentHeightWhenLoaded: newLatestContentHeightWhenLoaded
1674
1882
  };
1675
1883
  };
1676
- const defaultGetResource = (item) => new URL(item.href);
1677
- class ResourceHandler {
1678
- constructor(item, settings) {
1679
- this.item = item;
1680
- this.settings = settings;
1681
- }
1682
- async getResource() {
1683
- var _a, _b;
1684
- const resource = await lastValueFrom(
1685
- ((_b = (_a = this.settings.values).getResource) == null ? void 0 : _b.call(_a, this.item)) ?? of(void 0)
1686
- );
1687
- return resource ?? defaultGetResource(this.item);
1688
- }
1689
- async fetchResource() {
1690
- const resource = await this.getResource();
1691
- if (resource instanceof Response) return resource;
1692
- if (resource instanceof URL) return fetch(resource);
1693
- return resource;
1694
- }
1695
- }
1696
- const joinPath = (base, path) => {
1697
- const isFileProtocol = base.startsWith("file://");
1698
- const tempBase = isFileProtocol ? base.replace("file://", "http://") : base;
1699
- const result = new URL(path, tempBase).toString();
1700
- return isFileProtocol ? result.replace("http://", "file://") : result;
1701
- };
1702
- const getElementsWithAssets = (document2) => {
1703
- const RESOURCE_ELEMENTS = [
1704
- "img",
1705
- // Images
1706
- "video",
1707
- // Video files
1708
- "audio",
1709
- // Audio files
1710
- "source",
1711
- // Source elements within video/audio
1712
- "link",
1713
- // Stylesheets and other linked resources
1714
- "script"
1715
- // JavaScript files
1716
- ].join(",");
1717
- return Array.from((document2 == null ? void 0 : document2.querySelectorAll(RESOURCE_ELEMENTS)) || []);
1718
- };
1719
- const loadAssets = ({
1720
- settings,
1721
- item,
1722
- context
1723
- }) => (stream) => stream.pipe(
1724
- switchMap((frameElement) => {
1725
- const elementsWithAsset = getElementsWithAssets(
1726
- frameElement.contentDocument
1727
- );
1728
- const assetsLoad$ = Array.from(elementsWithAsset).map((element) => {
1729
- var _a;
1730
- const originalSrc = element.getAttribute("src") || element.getAttribute("href");
1731
- if (!originalSrc) return of(null);
1732
- const spineItemUriParentPath = getParentPath(item.href);
1733
- const foundItem = (_a = context.manifest) == null ? void 0 : _a.items.find(({ href }) => {
1734
- return `${joinPath(spineItemUriParentPath, originalSrc).toLowerCase()}`.endsWith(
1735
- `${href.toLowerCase()}`
1736
- );
1737
- });
1738
- if (!foundItem) return of(null);
1739
- const resourceHandler = new ResourceHandler(foundItem, settings);
1740
- return from(resourceHandler.getResource()).pipe(
1741
- mergeMap(
1742
- (resource) => resource instanceof Response ? from(resource.blob()) : of(void 0)
1743
- ),
1744
- tap$1((blob) => {
1745
- if (blob) {
1746
- const blobUrl = URL.createObjectURL(blob);
1747
- if (element.hasAttribute("src")) {
1748
- element.setAttribute("src", blobUrl);
1749
- } else if (element.hasAttribute("href")) {
1750
- element.setAttribute("href", blobUrl);
1751
- }
1752
- }
1753
- })
1754
- );
1755
- });
1756
- return combineLatest(assetsLoad$).pipe(map(() => frameElement));
1757
- })
1758
- );
1759
- const unloadMedias = (frameElement) => {
1760
- const elementsWithAsset = getElementsWithAssets(frameElement == null ? void 0 : frameElement.contentDocument);
1761
- elementsWithAsset.forEach((element) => {
1762
- const url = element.getAttribute("src") || element.getAttribute("href");
1763
- if (url == null ? void 0 : url.startsWith("blob:")) {
1764
- URL.revokeObjectURL(url);
1765
- }
1766
- });
1767
- };
1768
1884
  class HtmlRenderer extends DocumentRenderer {
1769
1885
  constructor() {
1770
1886
  super(...arguments);
@@ -1801,7 +1917,7 @@ class HtmlRenderer extends DocumentRenderer {
1801
1917
  );
1802
1918
  }
1803
1919
  onUnload() {
1804
- unloadMedias(this.getFrameElement());
1920
+ unloadAssets(this.getFrameElement());
1805
1921
  this.detach();
1806
1922
  return EMPTY;
1807
1923
  }
@@ -6285,196 +6401,51 @@ class UserNavigator extends DestroyableClass {
6285
6401
  this.navigationSubject.next(to);
6286
6402
  }
6287
6403
  }
6288
- const isRootCfi = (cfi) => {
6289
- return cfi == null ? void 0 : cfi.startsWith(`epubcfi(/0`);
6290
- };
6291
- const restoreNavigationForControlledPageTurnMode = ({
6292
- spineLocator,
6293
- navigation,
6294
- navigationResolver,
6295
- spineItemsManager,
6296
- spineLayout
6297
- }) => {
6298
- var _a, _b;
6299
- const spineItem = spineItemsManager.get(navigation.spineItem);
6300
- if (!spineItem) {
6301
- return { x: 0, y: 0 };
6302
- }
6303
- const spineItemAbsolutePosition = spineLayout.getAbsolutePositionOf(spineItem);
6304
- const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(
6305
- navigation.position,
6306
- spineItem
6404
+ const withPaginationInfo = () => (stream) => {
6405
+ return stream.pipe(
6406
+ map(({ navigation, pagination, ...rest }) => {
6407
+ return {
6408
+ navigation: {
6409
+ ...navigation,
6410
+ paginationBeginCfi: pagination.beginCfi
6411
+ },
6412
+ ...rest
6413
+ };
6414
+ })
6307
6415
  );
6308
- const spineItemWidthDifference = spineItemAbsolutePosition.width - (navigation.spineItemWidth ?? 0);
6309
- const spineItemHeighDifference = spineItemAbsolutePosition.height - (navigation.spineItemHeight ?? 0);
6310
- const hasSpineItemGrewOrShrink = spineItemWidthDifference !== 0 || spineItemHeighDifference !== 0;
6311
- if (navigation.url !== void 0) {
6312
- if (spineItemWidthDifference || spineItemHeighDifference) {
6313
- const urlResult = navigationResolver.getNavigationForUrl(navigation.url);
6314
- if (urlResult) {
6315
- return urlResult.position;
6316
- }
6317
- }
6318
- }
6319
- const cfi = navigation.cfi ?? navigation.paginationBeginCfi;
6320
- if (cfi !== void 0 && !isRootCfi(cfi)) {
6321
- if (spineItemWidthDifference || spineItemHeighDifference) {
6322
- const cfiResultPosition = navigationResolver.getNavigationForCfi(cfi);
6323
- if (cfiResultPosition) {
6324
- return cfiResultPosition;
6325
- }
6326
- }
6327
- }
6328
- if (isPositionWithinSpineItem && hasSpineItemGrewOrShrink && navigation.directionFromLastNavigation === "backward") {
6329
- const positionInSpineItemWithDifference = {
6330
- x: (((_a = navigation.positionInSpineItem) == null ? void 0 : _a.x) ?? 0) + spineItemWidthDifference,
6331
- y: (((_b = navigation.positionInSpineItem) == null ? void 0 : _b.y) ?? 0) + spineItemHeighDifference
6332
- };
6333
- return navigationResolver.getNavigationFromSpineItemPosition({
6334
- spineItem,
6335
- spineItemPosition: positionInSpineItemWithDifference
6336
- });
6337
- }
6338
- if (navigation.positionInSpineItem && navigation.spineItemHeight && navigation.spineItemWidth) {
6339
- const pageIndex = spineLocator.spineItemLocator.getSpineItemPageIndexFromPosition({
6340
- itemWidth: navigation.spineItemWidth,
6341
- itemHeight: navigation.spineItemHeight,
6342
- isUsingVerticalWriting: !!navigation.spineItemIsUsingVerticalWriting,
6343
- position: navigation.positionInSpineItem
6344
- });
6345
- return navigationResolver.getNavigationForSpineItemPage({
6346
- pageIndex,
6347
- spineItemId: spineItem
6348
- });
6349
- }
6350
- if (isPositionWithinSpineItem) {
6351
- return navigationResolver.getNavigationForPosition(navigation.position);
6352
- }
6353
- return navigationResolver.getNavigationForSpineIndexOrId(spineItem);
6354
6416
  };
6355
- const restoreNavigationForScrollingPageTurnMode = ({
6356
- navigation,
6357
- spineLocator,
6358
- spineItemsManager,
6359
- settings,
6360
- navigationResolver,
6361
- spineLayout
6362
- }) => {
6363
- const { spineItem } = navigation;
6364
- const foundSpineItem = spineItemsManager.get(spineItem);
6365
- if (!foundSpineItem) return { x: 0, y: 0 };
6366
- const { height, top } = spineLayout.getAbsolutePositionOf(foundSpineItem);
6367
- const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(
6368
- navigation.position,
6369
- foundSpineItem
6370
- );
6371
- const positionInSpineItem = navigation.positionInSpineItem ?? {
6372
- y: 0
6373
- };
6374
- if (settings.values.computedPageTurnDirection === "vertical") {
6375
- if (top === navigation.spineItemTop && height === navigation.spineItemHeight && isPositionWithinSpineItem) {
6376
- return navigation.position;
6377
- }
6378
- if (top === navigation.spineItemTop && height === navigation.spineItemHeight && !isPositionWithinSpineItem) {
6379
- return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem);
6380
- }
6381
- if (top !== navigation.spineItemTop) {
6382
- const positionInSpineItem2 = spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6383
- navigation.positionInSpineItem ?? {
6384
- x: 0,
6385
- y: 0
6386
- },
6387
- foundSpineItem
6388
- );
6389
- return spineLocator.getSpinePositionFromSpineItemPosition({
6390
- spineItemPosition: positionInSpineItem2,
6391
- spineItem: foundSpineItem
6392
- });
6393
- }
6394
- if (top === navigation.spineItemTop && height !== navigation.spineItemHeight) {
6395
- const positionYfromBottomPreviousNavigation = (navigation.spineItemHeight ?? positionInSpineItem.y) - positionInSpineItem.y;
6396
- const positionInspineItem = {
6397
- y: navigation.directionFromLastNavigation === "backward" ? height - positionYfromBottomPreviousNavigation : positionInSpineItem.y,
6398
- x: navigation.position.x
6399
- };
6400
- if (isPositionWithinSpineItem) {
6401
- const positionInSpineItem2 = spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6402
- positionInspineItem,
6403
- foundSpineItem
6404
- );
6405
- return spineLocator.getSpinePositionFromSpineItemPosition({
6406
- spineItemPosition: positionInSpineItem2,
6407
- spineItem: foundSpineItem
6408
- });
6409
- }
6410
- if (!isPositionWithinSpineItem) {
6411
- const positionIsBeforeItem = navigation.position.y < top;
6412
- if (!positionIsBeforeItem) {
6413
- const positionInItem = {
6414
- y: height - positionYfromBottomPreviousNavigation,
6415
- x: navigation.position.x
6416
- };
6417
- return spineLocator.getSpinePositionFromSpineItemPosition({
6418
- spineItemPosition: spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6419
- positionInItem,
6420
- foundSpineItem
6421
- ),
6422
- spineItem: foundSpineItem
6423
- });
6424
- }
6425
- return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem);
6417
+ const consolidateWithPagination = (context, navigation$, spine) => context.bridgeEvent.pagination$.pipe(
6418
+ withLatestFrom(navigation$),
6419
+ filter(
6420
+ ([pagination, navigation]) => pagination.navigationId === navigation.id
6421
+ ),
6422
+ /**
6423
+ * We only register the pagination cfi IF the spine item is ready.
6424
+ * Otherwise we might save something incomplete and thus restore
6425
+ * the user to an invalid location.
6426
+ */
6427
+ switchMap(([pagination, navigation]) => {
6428
+ const spineItem = spine.spineItemsManager.get(navigation.spineItem);
6429
+ return ((spineItem == null ? void 0 : spineItem.isReady$.pipe(first$1())) ?? of(false)).pipe(
6430
+ filter((isReady) => isReady),
6431
+ map(() => ({
6432
+ pagination,
6433
+ navigation
6434
+ }))
6435
+ );
6436
+ }),
6437
+ withPaginationInfo(),
6438
+ distinctUntilChanged$1(
6439
+ (prev, curr) => prev.navigation.paginationBeginCfi === curr.navigation.paginationBeginCfi
6440
+ ),
6441
+ map(
6442
+ ({ navigation }) => ({
6443
+ ...navigation,
6444
+ meta: {
6445
+ triggeredBy: "pagination"
6426
6446
  }
6427
- }
6428
- }
6429
- return navigation.position;
6430
- };
6431
- const restorePosition = ({
6432
- navigation,
6433
- spineItemsManager,
6434
- settings,
6435
- spineLocator,
6436
- navigationResolver,
6437
- spineLayout
6438
- }) => {
6439
- if (settings.values.computedPageTurnMode === "scrollable") {
6440
- return restoreNavigationForScrollingPageTurnMode({
6441
- navigation,
6442
- spineLocator,
6443
- navigationResolver,
6444
- settings,
6445
- spineItemsManager,
6446
- spineLayout
6447
- });
6448
- }
6449
- return restoreNavigationForControlledPageTurnMode({
6450
- navigation,
6451
- spineLocator,
6452
- navigationResolver,
6453
- spineItemsManager,
6454
- spineLayout
6455
- });
6456
- };
6457
- const withRestoredPosition = ({
6458
- settings,
6459
- navigationResolver,
6460
- context,
6461
- spine
6462
- }) => (stream) => stream.pipe(
6463
- map((params) => ({
6464
- ...params,
6465
- navigation: {
6466
- ...params.navigation,
6467
- position: restorePosition({
6468
- spineLocator: spine.locator,
6469
- navigation: params.navigation,
6470
- navigationResolver,
6471
- settings,
6472
- spineItemsManager: spine.spineItemsManager,
6473
- spineItemLocator: spine.locator.spineItemLocator,
6474
- spineLayout: spine.spineLayout
6475
- })
6476
- }
6477
- }))
6447
+ })
6448
+ )
6478
6449
  );
6479
6450
  const mapUserNavigationToInternal = (stream) => {
6480
6451
  return stream.pipe(
@@ -6495,6 +6466,27 @@ const mapUserNavigationToInternal = (stream) => {
6495
6466
  })
6496
6467
  );
6497
6468
  };
6469
+ const withCfiPosition = ({ navigationResolver }) => (stream) => {
6470
+ return stream.pipe(
6471
+ map((params) => {
6472
+ if (params.navigation.cfi) {
6473
+ const position = navigationResolver.getNavigationForCfi(
6474
+ params.navigation.cfi
6475
+ );
6476
+ if (position) {
6477
+ return {
6478
+ ...params,
6479
+ navigation: {
6480
+ ...params.navigation,
6481
+ position
6482
+ }
6483
+ };
6484
+ }
6485
+ }
6486
+ return params;
6487
+ })
6488
+ );
6489
+ };
6498
6490
  const getOrGuessDirection = ({
6499
6491
  navigation,
6500
6492
  previousNavigation,
@@ -6554,59 +6546,6 @@ const withDirection = ({
6554
6546
  })
6555
6547
  );
6556
6548
  };
6557
- const withSpineItemPosition = ({
6558
- settings,
6559
- spineItemsManager,
6560
- spineLocator,
6561
- navigationResolver
6562
- }) => (stream) => {
6563
- const getPosition = (navigation) => {
6564
- const { navigationSnapThreshold, computedPageTurnMode } = settings.values;
6565
- const spineItem = spineItemsManager.get(navigation.spineItem);
6566
- if (!spineItem || !navigation.position) return void 0;
6567
- if (computedPageTurnMode === "controlled") {
6568
- const { endPageIndex, beginPageIndex } = spineLocator.getVisiblePagesFromViewportPosition({
6569
- position: navigation.position,
6570
- spineItem,
6571
- threshold: navigationSnapThreshold,
6572
- restrictToScreen: false
6573
- }) ?? {};
6574
- const farthestPageIndex = (navigation.directionFromLastNavigation === "forward" || navigation.directionFromLastNavigation === "anchor" ? endPageIndex : beginPageIndex) ?? 0;
6575
- const navigableSpinePositionForFarthestPageIndex = navigationResolver.getNavigationForSpineItemPage({
6576
- pageIndex: farthestPageIndex,
6577
- spineItemId: spineItem
6578
- });
6579
- const visiblePagesAtNavigablePosition = spineLocator.getVisiblePagesFromViewportPosition({
6580
- position: navigableSpinePositionForFarthestPageIndex,
6581
- spineItem,
6582
- threshold: 0,
6583
- restrictToScreen: true
6584
- });
6585
- const beginPageIndexForDirection = (navigation.directionFromLastNavigation === "forward" || navigation.directionFromLastNavigation === "anchor" ? visiblePagesAtNavigablePosition == null ? void 0 : visiblePagesAtNavigablePosition.beginPageIndex : visiblePagesAtNavigablePosition == null ? void 0 : visiblePagesAtNavigablePosition.endPageIndex) ?? 0;
6586
- const positionInSpineItem = spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex({
6587
- pageIndex: beginPageIndexForDirection,
6588
- isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
6589
- itemLayout: spineItem.getElementDimensions()
6590
- });
6591
- return positionInSpineItem;
6592
- }
6593
- return spineLocator.getSpineItemPositionFromSpinePosition(
6594
- navigation.position,
6595
- spineItem
6596
- );
6597
- };
6598
- return stream.pipe(
6599
- map(({ navigation, ...rest }) => {
6600
- return {
6601
- navigation: {
6602
- ...navigation,
6603
- positionInSpineItem: getPosition(navigation)
6604
- },
6605
- ...rest
6606
- };
6607
- })
6608
- );
6609
- };
6610
6549
  const withFallbackPosition = ({
6611
6550
  spineItemsManager,
6612
6551
  navigationResolver
@@ -6643,70 +6582,6 @@ const withFallbackPosition = ({
6643
6582
  })
6644
6583
  );
6645
6584
  };
6646
- const withSpineItemLayoutInfo = ({ spine }) => (stream) => {
6647
- return stream.pipe(
6648
- map(({ navigation, ...rest }) => {
6649
- const spineItemDimensions = spine.spineLayout.getAbsolutePositionOf(
6650
- navigation.spineItem
6651
- );
6652
- const spineItem = spine.spineItemsManager.get(navigation.spineItem);
6653
- return {
6654
- navigation: {
6655
- ...navigation,
6656
- spineItemHeight: spineItemDimensions == null ? void 0 : spineItemDimensions.height,
6657
- spineItemWidth: spineItemDimensions == null ? void 0 : spineItemDimensions.width,
6658
- spineItemLeft: spineItemDimensions.left,
6659
- spineItemTop: spineItemDimensions.top,
6660
- spineItemIsUsingVerticalWriting: spineItem == null ? void 0 : spineItem.isUsingVerticalWriting()
6661
- },
6662
- ...rest
6663
- };
6664
- })
6665
- );
6666
- };
6667
- const withUrlInfo = ({ navigationResolver }) => (stream) => {
6668
- return stream.pipe(
6669
- map((params) => {
6670
- if (params.navigation.url) {
6671
- const result = navigationResolver.getNavigationForUrl(
6672
- params.navigation.url
6673
- );
6674
- if (result) {
6675
- return {
6676
- ...params,
6677
- navigation: {
6678
- ...params.navigation,
6679
- position: result.position,
6680
- spineItem: result.spineItemId
6681
- }
6682
- };
6683
- }
6684
- }
6685
- return params;
6686
- })
6687
- );
6688
- };
6689
- const withCfiPosition = ({ navigationResolver }) => (stream) => {
6690
- return stream.pipe(
6691
- map((params) => {
6692
- if (params.navigation.cfi) {
6693
- const position = navigationResolver.getNavigationForCfi(
6694
- params.navigation.cfi
6695
- );
6696
- if (position) {
6697
- return {
6698
- ...params,
6699
- navigation: {
6700
- ...params.navigation,
6701
- position
6702
- }
6703
- };
6704
- }
6705
- }
6706
- return params;
6707
- })
6708
- );
6709
- };
6710
6585
  const withSpineItem = ({
6711
6586
  settings,
6712
6587
  spineItemsManager,
@@ -6745,87 +6620,351 @@ const withSpineItem = ({
6745
6620
  const farthestSpineItem = spineItemsManager.get(farthestSpineItemIndex);
6746
6621
  if (!farthestSpineItem) return void 0;
6747
6622
  const { endPageIndex, beginPageIndex } = spineLocator.getVisiblePagesFromViewportPosition({
6748
- position,
6749
- spineItem: farthestSpineItem,
6623
+ position,
6624
+ spineItem: farthestSpineItem,
6625
+ threshold: navigationSnapThreshold,
6626
+ restrictToScreen: false
6627
+ }) ?? {};
6628
+ const farthestVisiblePageIndex = (direction === "forward" || direction === "anchor" ? endPageIndex : beginPageIndex) ?? 0;
6629
+ const navigationForPosition = navigationResolver.getNavigationForSpineItemPage({
6630
+ pageIndex: farthestVisiblePageIndex,
6631
+ spineItemId: farthestSpineItem
6632
+ });
6633
+ const visibleSpineItemsFromNavigablePosition = spineLocator.getVisibleSpineItemsFromPosition({
6634
+ position: navigationForPosition,
6635
+ threshold: navigationSnapThreshold,
6636
+ restrictToScreen: false
6637
+ });
6638
+ const finalSpineItemIndex = direction === "forward" || direction === "anchor" ? visibleSpineItemsFromNavigablePosition == null ? void 0 : visibleSpineItemsFromNavigablePosition.beginIndex : visibleSpineItemsFromNavigablePosition == null ? void 0 : visibleSpineItemsFromNavigablePosition.endIndex;
6639
+ return spineItemsManager.get(finalSpineItemIndex);
6640
+ }
6641
+ if (position && computedPageTurnMode === "scrollable") {
6642
+ return spineLocator.getSpineItemFromPosition(position);
6643
+ }
6644
+ return spineItemsManager.get(0);
6645
+ };
6646
+ return stream.pipe(
6647
+ map(({ navigation, ...rest }) => {
6648
+ const spineItem = getSpineItem(navigation);
6649
+ return {
6650
+ navigation: {
6651
+ ...navigation,
6652
+ spineItem: spineItemsManager.getSpineItemIndex(spineItem)
6653
+ },
6654
+ ...rest
6655
+ };
6656
+ })
6657
+ );
6658
+ };
6659
+ const withSpineItemLayoutInfo = ({ spine }) => (stream) => {
6660
+ return stream.pipe(
6661
+ switchMap(({ navigation, ...rest }) => {
6662
+ const spineItemDimensions = spine.spineLayout.getAbsolutePositionOf(
6663
+ navigation.spineItem
6664
+ );
6665
+ const spineItem = spine.spineItemsManager.get(navigation.spineItem);
6666
+ return ((spineItem == null ? void 0 : spineItem.isReady$) ?? of(false)).pipe(
6667
+ first$1(),
6668
+ map(
6669
+ (isReady) => ({
6670
+ navigation: {
6671
+ ...navigation,
6672
+ spineItemHeight: spineItemDimensions == null ? void 0 : spineItemDimensions.height,
6673
+ spineItemWidth: spineItemDimensions == null ? void 0 : spineItemDimensions.width,
6674
+ spineItemLeft: spineItemDimensions.left,
6675
+ spineItemTop: spineItemDimensions.top,
6676
+ spineItemIsUsingVerticalWriting: spineItem == null ? void 0 : spineItem.isUsingVerticalWriting(),
6677
+ spineItemIsReady: isReady
6678
+ },
6679
+ ...rest
6680
+ })
6681
+ )
6682
+ );
6683
+ })
6684
+ );
6685
+ };
6686
+ const withSpineItemPosition = ({
6687
+ settings,
6688
+ spineItemsManager,
6689
+ spineLocator,
6690
+ navigationResolver
6691
+ }) => (stream) => {
6692
+ const getPosition = (navigation) => {
6693
+ const { navigationSnapThreshold, computedPageTurnMode } = settings.values;
6694
+ const spineItem = spineItemsManager.get(navigation.spineItem);
6695
+ if (!spineItem || !navigation.position) return void 0;
6696
+ if (computedPageTurnMode === "controlled") {
6697
+ const { endPageIndex, beginPageIndex } = spineLocator.getVisiblePagesFromViewportPosition({
6698
+ position: navigation.position,
6699
+ spineItem,
6750
6700
  threshold: navigationSnapThreshold,
6751
6701
  restrictToScreen: false
6752
6702
  }) ?? {};
6753
- const farthestVisiblePageIndex = (direction === "forward" || direction === "anchor" ? endPageIndex : beginPageIndex) ?? 0;
6754
- const navigationForPosition = navigationResolver.getNavigationForSpineItemPage({
6755
- pageIndex: farthestVisiblePageIndex,
6756
- spineItemId: farthestSpineItem
6703
+ const farthestPageIndex = (navigation.directionFromLastNavigation === "forward" || navigation.directionFromLastNavigation === "anchor" ? endPageIndex : beginPageIndex) ?? 0;
6704
+ const navigableSpinePositionForFarthestPageIndex = navigationResolver.getNavigationForSpineItemPage({
6705
+ pageIndex: farthestPageIndex,
6706
+ spineItemId: spineItem
6757
6707
  });
6758
- const visibleSpineItemsFromNavigablePosition = spineLocator.getVisibleSpineItemsFromPosition({
6759
- position: navigationForPosition,
6760
- threshold: navigationSnapThreshold,
6761
- restrictToScreen: false
6708
+ const visiblePagesAtNavigablePosition = spineLocator.getVisiblePagesFromViewportPosition({
6709
+ position: navigableSpinePositionForFarthestPageIndex,
6710
+ spineItem,
6711
+ threshold: 0,
6712
+ restrictToScreen: true
6762
6713
  });
6763
- const finalSpineItemIndex = direction === "forward" || direction === "anchor" ? visibleSpineItemsFromNavigablePosition == null ? void 0 : visibleSpineItemsFromNavigablePosition.beginIndex : visibleSpineItemsFromNavigablePosition == null ? void 0 : visibleSpineItemsFromNavigablePosition.endIndex;
6764
- return spineItemsManager.get(finalSpineItemIndex);
6765
- }
6766
- if (position && computedPageTurnMode === "scrollable") {
6767
- return spineLocator.getSpineItemFromPosition(position);
6714
+ const beginPageIndexForDirection = (navigation.directionFromLastNavigation === "forward" || navigation.directionFromLastNavigation === "anchor" ? visiblePagesAtNavigablePosition == null ? void 0 : visiblePagesAtNavigablePosition.beginPageIndex : visiblePagesAtNavigablePosition == null ? void 0 : visiblePagesAtNavigablePosition.endPageIndex) ?? 0;
6715
+ const positionInSpineItem = spineLocator.spineItemLocator.getSpineItemPositionFromPageIndex({
6716
+ pageIndex: beginPageIndexForDirection,
6717
+ isUsingVerticalWriting: !!spineItem.isUsingVerticalWriting(),
6718
+ itemLayout: spineItem.getElementDimensions()
6719
+ });
6720
+ return positionInSpineItem;
6768
6721
  }
6769
- return spineItemsManager.get(0);
6722
+ return spineLocator.getSpineItemPositionFromSpinePosition(
6723
+ navigation.position,
6724
+ spineItem
6725
+ );
6770
6726
  };
6771
6727
  return stream.pipe(
6772
6728
  map(({ navigation, ...rest }) => {
6773
- const spineItem = getSpineItem(navigation);
6774
6729
  return {
6775
6730
  navigation: {
6776
6731
  ...navigation,
6777
- spineItem: spineItemsManager.getSpineItemIndex(spineItem)
6732
+ positionInSpineItem: getPosition(navigation)
6778
6733
  },
6779
6734
  ...rest
6780
6735
  };
6781
6736
  })
6782
6737
  );
6783
6738
  };
6784
- const withPaginationInfo = () => (stream) => {
6739
+ const withUrlInfo = ({ navigationResolver }) => (stream) => {
6785
6740
  return stream.pipe(
6786
- map(({ navigation, pagination, ...rest }) => {
6787
- return {
6788
- navigation: {
6789
- ...navigation,
6790
- paginationBeginCfi: pagination.beginCfi
6791
- },
6792
- ...rest
6793
- };
6741
+ map((params) => {
6742
+ if (params.navigation.url) {
6743
+ const result = navigationResolver.getNavigationForUrl(
6744
+ params.navigation.url
6745
+ );
6746
+ if (result) {
6747
+ return {
6748
+ ...params,
6749
+ navigation: {
6750
+ ...params.navigation,
6751
+ position: result.position,
6752
+ spineItem: result.spineItemId
6753
+ }
6754
+ };
6755
+ }
6756
+ }
6757
+ return params;
6794
6758
  })
6795
6759
  );
6796
6760
  };
6797
- const consolidateWithPagination = (context, navigation$, spine) => context.bridgeEvent.pagination$.pipe(
6798
- withLatestFrom(navigation$),
6799
- filter(
6800
- ([pagination, navigation]) => pagination.navigationId === navigation.id
6801
- ),
6802
- /**
6803
- * We only register the pagination cfi IF the spine item is ready.
6804
- * Otherwise we might save something incomplete and thus restore
6805
- * the user to an invalid location.
6806
- */
6807
- switchMap(([pagination, navigation]) => {
6808
- const spineItem = spine.spineItemsManager.get(navigation.spineItem);
6809
- return ((spineItem == null ? void 0 : spineItem.isReady$.pipe(first$1())) ?? of(false)).pipe(
6810
- filter((isReady) => isReady),
6811
- map(() => ({
6812
- pagination,
6813
- navigation
6814
- }))
6815
- );
6816
- }),
6817
- withPaginationInfo(),
6818
- distinctUntilChanged$1(
6819
- (prev, curr) => prev.navigation.paginationBeginCfi === curr.navigation.paginationBeginCfi
6820
- ),
6821
- map(
6822
- ({ navigation }) => ({
6823
- ...navigation,
6824
- meta: {
6825
- triggeredBy: "pagination"
6761
+ const isRootCfi = (cfi) => {
6762
+ return cfi == null ? void 0 : cfi.startsWith(`epubcfi(/0`);
6763
+ };
6764
+ const restoreNavigationForControlledPageTurnMode = ({
6765
+ spineLocator,
6766
+ navigation,
6767
+ navigationResolver,
6768
+ spineItemsManager,
6769
+ spineLayout
6770
+ }) => {
6771
+ const spineItem = spineItemsManager.get(navigation.spineItem);
6772
+ if (!spineItem) {
6773
+ return of({ x: 0, y: 0 });
6774
+ }
6775
+ return spineItem.isReady$.pipe(
6776
+ first$1(),
6777
+ map((isReady) => {
6778
+ var _a, _b;
6779
+ const spineItemAbsolutePosition = spineLayout.getAbsolutePositionOf(spineItem);
6780
+ const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(
6781
+ navigation.position,
6782
+ spineItem
6783
+ );
6784
+ const spineItemWidthDifference = spineItemAbsolutePosition.width - (navigation.spineItemWidth ?? 0);
6785
+ const spineItemHeighDifference = spineItemAbsolutePosition.height - (navigation.spineItemHeight ?? 0);
6786
+ const hasSpineItemGrewOrShrink = spineItemWidthDifference !== 0 || spineItemHeighDifference !== 0;
6787
+ if (navigation.url !== void 0) {
6788
+ if (spineItemWidthDifference || spineItemHeighDifference || // when spine item is ready dimensions may have not changed but the position
6789
+ // of dom elements may have!
6790
+ isReady && !navigation.spineItemIsReady) {
6791
+ const urlResult = navigationResolver.getNavigationForUrl(
6792
+ navigation.url
6793
+ );
6794
+ if (urlResult) {
6795
+ return urlResult.position;
6796
+ }
6797
+ }
6798
+ }
6799
+ const cfi = navigation.cfi ?? navigation.paginationBeginCfi;
6800
+ if (cfi !== void 0 && !isRootCfi(cfi)) {
6801
+ if (spineItemWidthDifference || spineItemHeighDifference || // when spine item is ready dimensions may have not changed but the position
6802
+ // of dom elements may have!
6803
+ isReady && !navigation.spineItemIsReady) {
6804
+ const cfiResultPosition = navigationResolver.getNavigationForCfi(cfi);
6805
+ if (cfiResultPosition) {
6806
+ return cfiResultPosition;
6807
+ }
6808
+ }
6809
+ }
6810
+ if (isPositionWithinSpineItem && hasSpineItemGrewOrShrink && navigation.directionFromLastNavigation === "backward") {
6811
+ const positionInSpineItemWithDifference = {
6812
+ x: (((_a = navigation.positionInSpineItem) == null ? void 0 : _a.x) ?? 0) + spineItemWidthDifference,
6813
+ y: (((_b = navigation.positionInSpineItem) == null ? void 0 : _b.y) ?? 0) + spineItemHeighDifference
6814
+ };
6815
+ return navigationResolver.getNavigationFromSpineItemPosition({
6816
+ spineItem,
6817
+ spineItemPosition: positionInSpineItemWithDifference
6818
+ });
6819
+ }
6820
+ if (navigation.positionInSpineItem && navigation.spineItemHeight && navigation.spineItemWidth) {
6821
+ const pageIndex = spineLocator.spineItemLocator.getSpineItemPageIndexFromPosition({
6822
+ itemWidth: navigation.spineItemWidth,
6823
+ itemHeight: navigation.spineItemHeight,
6824
+ isUsingVerticalWriting: !!navigation.spineItemIsUsingVerticalWriting,
6825
+ position: navigation.positionInSpineItem
6826
+ });
6827
+ return navigationResolver.getNavigationForSpineItemPage({
6828
+ pageIndex,
6829
+ spineItemId: spineItem
6830
+ });
6826
6831
  }
6832
+ if (isPositionWithinSpineItem) {
6833
+ return navigationResolver.getNavigationForPosition(navigation.position);
6834
+ }
6835
+ return navigationResolver.getNavigationForSpineIndexOrId(spineItem);
6827
6836
  })
6828
- )
6837
+ );
6838
+ };
6839
+ const restoreNavigationForScrollingPageTurnMode = ({
6840
+ navigation,
6841
+ spineLocator,
6842
+ spineItemsManager,
6843
+ settings,
6844
+ navigationResolver,
6845
+ spineLayout
6846
+ }) => {
6847
+ const { spineItem } = navigation;
6848
+ const foundSpineItem = spineItemsManager.get(spineItem);
6849
+ if (!foundSpineItem) return { x: 0, y: 0 };
6850
+ const { height, top } = spineLayout.getAbsolutePositionOf(foundSpineItem);
6851
+ const isPositionWithinSpineItem = spineLocator.isPositionWithinSpineItem(
6852
+ navigation.position,
6853
+ foundSpineItem
6854
+ );
6855
+ const positionInSpineItem = navigation.positionInSpineItem ?? {
6856
+ y: 0
6857
+ };
6858
+ if (settings.values.computedPageTurnDirection === "vertical") {
6859
+ if (top === navigation.spineItemTop && height === navigation.spineItemHeight && isPositionWithinSpineItem) {
6860
+ return navigation.position;
6861
+ }
6862
+ if (top === navigation.spineItemTop && height === navigation.spineItemHeight && !isPositionWithinSpineItem) {
6863
+ return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem);
6864
+ }
6865
+ if (top !== navigation.spineItemTop) {
6866
+ const positionInSpineItem2 = spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6867
+ navigation.positionInSpineItem ?? {
6868
+ x: 0,
6869
+ y: 0
6870
+ },
6871
+ foundSpineItem
6872
+ );
6873
+ return spineLocator.getSpinePositionFromSpineItemPosition({
6874
+ spineItemPosition: positionInSpineItem2,
6875
+ spineItem: foundSpineItem
6876
+ });
6877
+ }
6878
+ if (top === navigation.spineItemTop && height !== navigation.spineItemHeight) {
6879
+ const positionYfromBottomPreviousNavigation = (navigation.spineItemHeight ?? positionInSpineItem.y) - positionInSpineItem.y;
6880
+ const positionInspineItem = {
6881
+ y: navigation.directionFromLastNavigation === "backward" ? height - positionYfromBottomPreviousNavigation : positionInSpineItem.y,
6882
+ x: navigation.position.x
6883
+ };
6884
+ if (isPositionWithinSpineItem) {
6885
+ const positionInSpineItem2 = spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6886
+ positionInspineItem,
6887
+ foundSpineItem
6888
+ );
6889
+ return spineLocator.getSpinePositionFromSpineItemPosition({
6890
+ spineItemPosition: positionInSpineItem2,
6891
+ spineItem: foundSpineItem
6892
+ });
6893
+ }
6894
+ if (!isPositionWithinSpineItem) {
6895
+ const positionIsBeforeItem = navigation.position.y < top;
6896
+ if (!positionIsBeforeItem) {
6897
+ const positionInItem = {
6898
+ y: height - positionYfromBottomPreviousNavigation,
6899
+ x: navigation.position.x
6900
+ };
6901
+ return spineLocator.getSpinePositionFromSpineItemPosition({
6902
+ spineItemPosition: spineLocator.getSafeSpineItemPositionFromUnsafeSpineItemPosition(
6903
+ positionInItem,
6904
+ foundSpineItem
6905
+ ),
6906
+ spineItem: foundSpineItem
6907
+ });
6908
+ }
6909
+ return navigationResolver.getNavigationForSpineIndexOrId(foundSpineItem);
6910
+ }
6911
+ }
6912
+ }
6913
+ return navigation.position;
6914
+ };
6915
+ const restorePosition = ({
6916
+ navigation,
6917
+ spineItemsManager,
6918
+ settings,
6919
+ spineLocator,
6920
+ navigationResolver,
6921
+ spineLayout
6922
+ }) => {
6923
+ if (settings.values.computedPageTurnMode === "scrollable") {
6924
+ return of(
6925
+ restoreNavigationForScrollingPageTurnMode({
6926
+ navigation,
6927
+ spineLocator,
6928
+ navigationResolver,
6929
+ settings,
6930
+ spineItemsManager,
6931
+ spineLayout
6932
+ })
6933
+ );
6934
+ }
6935
+ return restoreNavigationForControlledPageTurnMode({
6936
+ navigation,
6937
+ spineLocator,
6938
+ navigationResolver,
6939
+ spineItemsManager,
6940
+ spineLayout
6941
+ });
6942
+ };
6943
+ const withRestoredPosition = ({
6944
+ settings,
6945
+ navigationResolver,
6946
+ context,
6947
+ spine
6948
+ }) => (stream) => stream.pipe(
6949
+ switchMap((params) => {
6950
+ return restorePosition({
6951
+ spineLocator: spine.locator,
6952
+ navigation: params.navigation,
6953
+ navigationResolver,
6954
+ settings,
6955
+ spineItemsManager: spine.spineItemsManager,
6956
+ spineItemLocator: spine.locator.spineItemLocator,
6957
+ spineLayout: spine.spineLayout
6958
+ }).pipe(
6959
+ map((restoredPosition) => ({
6960
+ ...params,
6961
+ navigation: {
6962
+ ...params.navigation,
6963
+ position: restoredPosition
6964
+ }
6965
+ }))
6966
+ );
6967
+ })
6829
6968
  );
6830
6969
  const NAMESPACE$2 = `navigation/InternalNavigator`;
6831
6970
  const report$1 = Report.namespace(NAMESPACE$2);
@@ -6846,6 +6985,7 @@ class InternalNavigator extends DestroyableClass {
6846
6985
  meta: {
6847
6986
  triggeredBy: "user"
6848
6987
  },
6988
+ spineItemIsReady: false,
6849
6989
  type: "api",
6850
6990
  id: Symbol()
6851
6991
  });
@@ -6861,10 +7001,6 @@ class InternalNavigator extends DestroyableClass {
6861
7001
  shareReplay$1(1)
6862
7002
  );
6863
7003
  this.locker = new Locker();
6864
- const layoutHasChanged$ = merge(
6865
- viewportController.layout$,
6866
- spine.spineLayout.layout$.pipe(filter(({ hasChanged }) => hasChanged))
6867
- );
6868
7004
  const navigationFromUser$ = userNavigation$.pipe(
6869
7005
  withLatestFrom(this.navigationSubject),
6870
7006
  mapUserNavigationToInternal,
@@ -6946,7 +7082,10 @@ class InternalNavigator extends DestroyableClass {
6946
7082
  }),
6947
7083
  share()
6948
7084
  );
6949
- const navigationUpateFromLayout$ = layoutHasChanged$.pipe(
7085
+ const navigationUpateFromLayout$ = merge(
7086
+ viewportController.layout$,
7087
+ spine.spineLayout.layout$
7088
+ ).pipe(
6950
7089
  switchMap(() => {
6951
7090
  return of(null).pipe(
6952
7091
  switchMap(