@inertiajs/core 2.1.11 → 2.2.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.esm.js CHANGED
@@ -1,3 +1,6 @@
1
+ // src/router.ts
2
+ import { cloneDeep as cloneDeep2, get as get2, set as set2 } from "lodash-es";
3
+
1
4
  // src/debounce.ts
2
5
  function debounce(fn, delay) {
3
6
  let timeoutID;
@@ -26,6 +29,9 @@ var fireFinishEvent = (visit) => {
26
29
  var fireInvalidEvent = (response) => {
27
30
  return fireEvent("invalid", { cancelable: true, detail: { response } });
28
31
  };
32
+ var fireBeforeUpdateEvent = (page2) => {
33
+ return fireEvent("beforeUpdate", { detail: { page: page2 } });
34
+ };
29
35
  var fireNavigateEvent = (page2) => {
30
36
  return fireEvent("navigate", { detail: { page: page2 } });
31
37
  };
@@ -1188,6 +1194,7 @@ var PrefetchedRequests = class {
1188
1194
  "replace",
1189
1195
  "prefetch",
1190
1196
  "onBefore",
1197
+ "onBeforeUpdate",
1191
1198
  "onStart",
1192
1199
  "onProgress",
1193
1200
  "onFinish",
@@ -1216,6 +1223,7 @@ var RequestParams = class _RequestParams {
1216
1223
  } else {
1217
1224
  const wrappedCallbacks = {
1218
1225
  onBefore: this.wrapCallback(params, "onBefore"),
1226
+ onBeforeUpdate: this.wrapCallback(params, "onBeforeUpdate"),
1219
1227
  onStart: this.wrapCallback(params, "onStart"),
1220
1228
  onProgress: this.wrapCallback(params, "onProgress"),
1221
1229
  onFinish: this.wrapCallback(params, "onFinish"),
@@ -1346,6 +1354,9 @@ var RequestParams = class _RequestParams {
1346
1354
  }
1347
1355
  };
1348
1356
 
1357
+ // src/response.ts
1358
+ import { get, set } from "lodash-es";
1359
+
1349
1360
  // src/modal.ts
1350
1361
  var modal_default = {
1351
1362
  modal: null,
@@ -1508,6 +1519,8 @@ var Response = class _Response {
1508
1519
  await this.setRememberedState(pageResponse);
1509
1520
  this.requestParams.setPreserveOptions(pageResponse);
1510
1521
  pageResponse.url = history.preserveUrl ? page.get().url : this.pageUrl(pageResponse);
1522
+ this.requestParams.all().onBeforeUpdate(pageResponse);
1523
+ fireBeforeUpdateEvent(pageResponse);
1511
1524
  return page.set(pageResponse, {
1512
1525
  replace: this.requestParams.all().replace,
1513
1526
  preserveScroll: this.requestParams.all().preserveScroll,
@@ -1547,36 +1560,43 @@ var Response = class _Response {
1547
1560
  if (!this.requestParams.isPartial() || pageResponse.component !== page.get().component) {
1548
1561
  return;
1549
1562
  }
1550
- const propsToMerge = pageResponse.mergeProps || [];
1563
+ const propsToAppend = pageResponse.mergeProps || [];
1564
+ const propsToPrepend = pageResponse.prependProps || [];
1551
1565
  const propsToDeepMerge = pageResponse.deepMergeProps || [];
1552
1566
  const matchPropsOn = pageResponse.matchPropsOn || [];
1553
- propsToMerge.forEach((prop) => {
1554
- const incomingProp = pageResponse.props[prop];
1567
+ const mergeProp = (prop, shouldAppend) => {
1568
+ const currentProp = get(page.get().props, prop);
1569
+ const incomingProp = get(pageResponse.props, prop);
1555
1570
  if (Array.isArray(incomingProp)) {
1556
- pageResponse.props[prop] = this.mergeOrMatchItems(
1557
- page.get().props[prop] || [],
1571
+ const newArray = this.mergeOrMatchItems(
1572
+ currentProp || [],
1558
1573
  incomingProp,
1559
1574
  prop,
1560
- matchPropsOn
1575
+ matchPropsOn,
1576
+ shouldAppend
1561
1577
  );
1578
+ set(pageResponse.props, prop, newArray);
1562
1579
  } else if (typeof incomingProp === "object" && incomingProp !== null) {
1563
- pageResponse.props[prop] = {
1564
- ...page.get().props[prop] || [],
1580
+ const newObject = {
1581
+ ...currentProp || {},
1565
1582
  ...incomingProp
1566
1583
  };
1584
+ set(pageResponse.props, prop, newObject);
1567
1585
  }
1568
- });
1586
+ };
1587
+ propsToAppend.forEach((prop) => mergeProp(prop, true));
1588
+ propsToPrepend.forEach((prop) => mergeProp(prop, false));
1569
1589
  propsToDeepMerge.forEach((prop) => {
1570
- const incomingProp = pageResponse.props[prop];
1571
1590
  const currentProp = page.get().props[prop];
1572
- const deepMerge = (target, source, currentKey) => {
1591
+ const incomingProp = pageResponse.props[prop];
1592
+ const deepMerge = (target, source, matchProp) => {
1573
1593
  if (Array.isArray(source)) {
1574
- return this.mergeOrMatchItems(target, source, currentKey, matchPropsOn);
1594
+ return this.mergeOrMatchItems(target, source, matchProp, matchPropsOn);
1575
1595
  }
1576
1596
  if (typeof source === "object" && source !== null) {
1577
1597
  return Object.keys(source).reduce(
1578
1598
  (acc, key) => {
1579
- acc[key] = deepMerge(target ? target[key] : void 0, source[key], `${currentKey}.${key}`);
1599
+ acc[key] = deepMerge(target ? target[key] : void 0, source[key], `${matchProp}.${key}`);
1580
1600
  return acc;
1581
1601
  },
1582
1602
  { ...target }
@@ -1588,32 +1608,52 @@ var Response = class _Response {
1588
1608
  });
1589
1609
  pageResponse.props = { ...page.get().props, ...pageResponse.props };
1590
1610
  }
1591
- mergeOrMatchItems(target, source, currentKey, matchPropsOn) {
1592
- const matchOn = matchPropsOn.find((key) => {
1593
- const path = key.split(".").slice(0, -1).join(".");
1594
- return path === currentKey;
1611
+ mergeOrMatchItems(existingItems, newItems, matchProp, matchPropsOn, shouldAppend = true) {
1612
+ const items = Array.isArray(existingItems) ? existingItems : [];
1613
+ const matchingKey = matchPropsOn.find((key) => {
1614
+ const keyPath = key.split(".").slice(0, -1).join(".");
1615
+ return keyPath === matchProp;
1595
1616
  });
1596
- if (!matchOn) {
1597
- return [...Array.isArray(target) ? target : [], ...source];
1598
- }
1599
- const uniqueProperty = matchOn.split(".").pop() || "";
1600
- const targetArray = Array.isArray(target) ? target : [];
1601
- const map = /* @__PURE__ */ new Map();
1602
- targetArray.forEach((item) => {
1603
- if (item && typeof item === "object" && uniqueProperty in item) {
1604
- map.set(item[uniqueProperty], item);
1605
- } else {
1606
- map.set(Symbol(), item);
1617
+ if (!matchingKey) {
1618
+ return shouldAppend ? [...items, ...newItems] : [...newItems, ...items];
1619
+ }
1620
+ const uniqueProperty = matchingKey.split(".").pop() || "";
1621
+ const newItemsMap = /* @__PURE__ */ new Map();
1622
+ newItems.forEach((item) => {
1623
+ if (this.hasUniqueProperty(item, uniqueProperty)) {
1624
+ newItemsMap.set(item[uniqueProperty], item);
1607
1625
  }
1608
1626
  });
1609
- source.forEach((item) => {
1610
- if (item && typeof item === "object" && uniqueProperty in item) {
1611
- map.set(item[uniqueProperty], item);
1612
- } else {
1613
- map.set(Symbol(), item);
1627
+ return shouldAppend ? this.appendWithMatching(items, newItems, newItemsMap, uniqueProperty) : this.prependWithMatching(items, newItems, newItemsMap, uniqueProperty);
1628
+ }
1629
+ appendWithMatching(existingItems, newItems, newItemsMap, uniqueProperty) {
1630
+ const updatedExisting = existingItems.map((item) => {
1631
+ if (this.hasUniqueProperty(item, uniqueProperty) && newItemsMap.has(item[uniqueProperty])) {
1632
+ return newItemsMap.get(item[uniqueProperty]);
1633
+ }
1634
+ return item;
1635
+ });
1636
+ const newItemsToAdd = newItems.filter((item) => {
1637
+ if (!this.hasUniqueProperty(item, uniqueProperty)) {
1638
+ return true;
1614
1639
  }
1640
+ return !existingItems.some(
1641
+ (existing) => this.hasUniqueProperty(existing, uniqueProperty) && existing[uniqueProperty] === item[uniqueProperty]
1642
+ );
1615
1643
  });
1616
- return Array.from(map.values());
1644
+ return [...updatedExisting, ...newItemsToAdd];
1645
+ }
1646
+ prependWithMatching(existingItems, newItems, newItemsMap, uniqueProperty) {
1647
+ const untouchedExisting = existingItems.filter((item) => {
1648
+ if (this.hasUniqueProperty(item, uniqueProperty)) {
1649
+ return !newItemsMap.has(item[uniqueProperty]);
1650
+ }
1651
+ return true;
1652
+ });
1653
+ return [...newItems, ...untouchedExisting];
1654
+ }
1655
+ hasUniqueProperty(item, property) {
1656
+ return item && typeof item === "object" && property in item;
1617
1657
  }
1618
1658
  async setRememberedState(pageResponse) {
1619
1659
  const rememberedState = await history.getState(history.rememberedState, {});
@@ -1955,6 +1995,43 @@ var Router = class {
1955
1995
  replace(params) {
1956
1996
  this.clientVisit(params, { replace: true });
1957
1997
  }
1998
+ replaceProp(name, value, options) {
1999
+ this.replace({
2000
+ preserveScroll: true,
2001
+ preserveState: true,
2002
+ props(currentProps) {
2003
+ const newValue = typeof value === "function" ? value(get2(currentProps, name), currentProps) : value;
2004
+ return set2(cloneDeep2(currentProps), name, newValue);
2005
+ },
2006
+ ...options || {}
2007
+ });
2008
+ }
2009
+ appendToProp(name, value, options) {
2010
+ this.replaceProp(
2011
+ name,
2012
+ (currentValue, currentProps) => {
2013
+ const newValue = typeof value === "function" ? value(currentValue, currentProps) : value;
2014
+ if (!Array.isArray(currentValue)) {
2015
+ currentValue = currentValue !== void 0 ? [currentValue] : [];
2016
+ }
2017
+ return [...currentValue, newValue];
2018
+ },
2019
+ options
2020
+ );
2021
+ }
2022
+ prependToProp(name, value, options) {
2023
+ this.replaceProp(
2024
+ name,
2025
+ (currentValue, currentProps) => {
2026
+ const newValue = typeof value === "function" ? value(currentValue, currentProps) : value;
2027
+ if (!Array.isArray(currentValue)) {
2028
+ currentValue = currentValue !== void 0 ? [currentValue] : [];
2029
+ }
2030
+ return [newValue, ...currentValue];
2031
+ },
2032
+ options
2033
+ );
2034
+ }
1958
2035
  push(params) {
1959
2036
  this.clientVisit(params);
1960
2037
  }
@@ -2047,6 +2124,8 @@ var Router = class {
2047
2124
  }),
2048
2125
  onBefore: options.onBefore || (() => {
2049
2126
  }),
2127
+ onBeforeUpdate: options.onBeforeUpdate || (() => {
2128
+ }),
2050
2129
  onStart: options.onStart || (() => {
2051
2130
  }),
2052
2131
  onProgress: options.onProgress || (() => {
@@ -2074,8 +2153,48 @@ var Router = class {
2074
2153
  }
2075
2154
  };
2076
2155
 
2156
+ // src/domUtils.ts
2157
+ var elementInViewport = (el) => {
2158
+ const rect = el.getBoundingClientRect();
2159
+ const verticallyVisible = rect.top < window.innerHeight && rect.bottom >= 0;
2160
+ const horizontallyVisible = rect.left < window.innerWidth && rect.right >= 0;
2161
+ return verticallyVisible && horizontallyVisible;
2162
+ };
2163
+ var getScrollableParent = (element) => {
2164
+ let parent = element?.parentElement;
2165
+ while (parent) {
2166
+ const overflowY = window.getComputedStyle(parent).overflowY;
2167
+ if (overflowY === "auto" || overflowY === "scroll") {
2168
+ return parent;
2169
+ }
2170
+ parent = parent.parentElement;
2171
+ }
2172
+ return null;
2173
+ };
2174
+ var getElementsInViewportFromCollection = (referenceElement, elements) => {
2175
+ const referenceIndex = elements.indexOf(referenceElement);
2176
+ const visibleElements = [];
2177
+ for (let i = referenceIndex; i >= 0; i--) {
2178
+ const element = elements[i];
2179
+ if (elementInViewport(element)) {
2180
+ visibleElements.push(element);
2181
+ } else {
2182
+ break;
2183
+ }
2184
+ }
2185
+ for (let i = referenceIndex + 1; i < elements.length; i++) {
2186
+ const element = elements[i];
2187
+ if (elementInViewport(element)) {
2188
+ visibleElements.push(element);
2189
+ } else {
2190
+ break;
2191
+ }
2192
+ }
2193
+ return visibleElements;
2194
+ };
2195
+
2077
2196
  // src/formObject.ts
2078
- import { get, set } from "lodash-es";
2197
+ import { get as get3, set as set3 } from "lodash-es";
2079
2198
  function undotKey(key) {
2080
2199
  if (!key.includes(".")) {
2081
2200
  return key;
@@ -2110,15 +2229,15 @@ function formDataToObject(source) {
2110
2229
  const path = parseKey(undotKey(key));
2111
2230
  if (path[path.length - 1] === "") {
2112
2231
  const arrayPath = path.slice(0, -1);
2113
- const existing = get(form, arrayPath);
2232
+ const existing = get3(form, arrayPath);
2114
2233
  if (Array.isArray(existing)) {
2115
2234
  existing.push(value);
2116
2235
  } else {
2117
- set(form, arrayPath, [value]);
2236
+ set3(form, arrayPath, [value]);
2118
2237
  }
2119
2238
  continue;
2120
2239
  }
2121
- set(form, path, value);
2240
+ set3(form, path, value);
2122
2241
  }
2123
2242
  return form;
2124
2243
  }
@@ -2235,6 +2354,380 @@ function createHeadManager(isServer2, titleCallback, onUpdate) {
2235
2354
  };
2236
2355
  }
2237
2356
 
2357
+ // src/infiniteScroll/data.ts
2358
+ var MERGE_INTENT_HEADER = "X-Inertia-Infinite-Scroll-Merge-Intent";
2359
+ var useInfiniteScrollData = (options) => {
2360
+ const getScrollPropFromCurrentPage = () => {
2361
+ const scrollProp = page.get().scrollProps?.[options.getPropName()];
2362
+ if (scrollProp) {
2363
+ return scrollProp;
2364
+ }
2365
+ throw new Error(`The page object does not contain a scroll prop named "${options.getPropName()}".`);
2366
+ };
2367
+ const { previousPage, nextPage, currentPage: lastLoadedPage } = getScrollPropFromCurrentPage();
2368
+ const state = {
2369
+ loading: false,
2370
+ previousPage,
2371
+ nextPage,
2372
+ lastLoadedPage
2373
+ };
2374
+ const getScrollPropKeyForSide = (side) => {
2375
+ return side === "next" ? "nextPage" : "previousPage";
2376
+ };
2377
+ const findPageToLoad = (side) => {
2378
+ const pagePropName = getScrollPropKeyForSide(side);
2379
+ return state[pagePropName];
2380
+ };
2381
+ const syncStateOnSuccess = (side) => {
2382
+ const scrollProp = getScrollPropFromCurrentPage();
2383
+ const paginationProp = getScrollPropKeyForSide(side);
2384
+ state.lastLoadedPage = scrollProp.currentPage;
2385
+ state[paginationProp] = scrollProp[paginationProp];
2386
+ };
2387
+ const getPageName = () => getScrollPropFromCurrentPage().pageName;
2388
+ const fetchPage = (side, reloadOptions = {}) => {
2389
+ const page2 = findPageToLoad(side);
2390
+ if (state.loading || page2 === null) {
2391
+ return;
2392
+ }
2393
+ state.loading = true;
2394
+ router.reload({
2395
+ ...reloadOptions,
2396
+ data: { [getPageName()]: page2 },
2397
+ only: [options.getPropName()],
2398
+ preserveUrl: true,
2399
+ // we handle URL updates manually via useInfiniteScrollQueryString()
2400
+ headers: {
2401
+ [MERGE_INTENT_HEADER]: side === "previous" ? "prepend" : "append",
2402
+ ...reloadOptions.headers
2403
+ },
2404
+ onBefore: (visit) => {
2405
+ side === "next" ? options.onBeforeNextRequest() : options.onBeforePreviousRequest();
2406
+ reloadOptions.onBefore?.(visit);
2407
+ },
2408
+ onBeforeUpdate: (page3) => {
2409
+ options.onBeforeUpdate();
2410
+ reloadOptions.onBeforeUpdate?.(page3);
2411
+ },
2412
+ onSuccess: (page3) => {
2413
+ syncStateOnSuccess(side);
2414
+ reloadOptions.onSuccess?.(page3);
2415
+ },
2416
+ onFinish: (visit) => {
2417
+ state.loading = false;
2418
+ side === "next" ? options.onCompleteNextRequest(state.lastLoadedPage) : options.onCompletePreviousRequest(state.lastLoadedPage);
2419
+ reloadOptions.onFinish?.(visit);
2420
+ }
2421
+ });
2422
+ };
2423
+ const getLastLoadedPage = () => state.lastLoadedPage;
2424
+ const hasPrevious = () => !!state.previousPage;
2425
+ const hasNext = () => !!state.nextPage;
2426
+ const fetchPrevious = (reloadOptions) => fetchPage("previous", reloadOptions);
2427
+ const fetchNext = (reloadOptions) => fetchPage("next", reloadOptions);
2428
+ return {
2429
+ getLastLoadedPage,
2430
+ getPageName,
2431
+ hasPrevious,
2432
+ hasNext,
2433
+ fetchNext,
2434
+ fetchPrevious
2435
+ };
2436
+ };
2437
+
2438
+ // src/intersectionObservers.ts
2439
+ var useIntersectionObservers = () => {
2440
+ const intersectionObservers = [];
2441
+ const newIntersectionObserver = (callback, options = {}) => {
2442
+ const observer = new IntersectionObserver((entries) => {
2443
+ for (const entry of entries) {
2444
+ if (entry.isIntersecting) {
2445
+ callback(entry);
2446
+ }
2447
+ }
2448
+ }, options);
2449
+ intersectionObservers.push(observer);
2450
+ return observer;
2451
+ };
2452
+ const flushAll = () => {
2453
+ intersectionObservers.forEach((observer) => observer.disconnect());
2454
+ intersectionObservers.length = 0;
2455
+ };
2456
+ return {
2457
+ new: newIntersectionObserver,
2458
+ flushAll
2459
+ };
2460
+ };
2461
+
2462
+ // src/infiniteScroll/elements.ts
2463
+ var INFINITE_SCROLL_PAGE_KEY = "infiniteScrollPage";
2464
+ var INFINITE_SCROLL_IGNORE_KEY = "infiniteScrollIgnore";
2465
+ var getPageFromElement = (element) => element.dataset[INFINITE_SCROLL_PAGE_KEY];
2466
+ var useInfiniteScrollElementManager = (options) => {
2467
+ const intersectionObservers = useIntersectionObservers();
2468
+ let itemsObserver;
2469
+ let startElementObserver;
2470
+ let endElementObserver;
2471
+ let itemsMutationObserver;
2472
+ let triggersEnabled = false;
2473
+ const setupObservers = () => {
2474
+ itemsMutationObserver = new MutationObserver((mutations) => {
2475
+ mutations.forEach((mutation) => {
2476
+ mutation.addedNodes.forEach((node) => {
2477
+ if (node.nodeType === Node.ELEMENT_NODE) {
2478
+ addedElements.add(node);
2479
+ }
2480
+ });
2481
+ });
2482
+ });
2483
+ itemsMutationObserver.observe(options.getItemsElement(), { childList: true });
2484
+ itemsObserver = intersectionObservers.new(
2485
+ (entry) => options.onItemIntersected(entry.target),
2486
+ { threshold: 0 }
2487
+ );
2488
+ const observerOptions = {
2489
+ root: options.getScrollableParent(),
2490
+ rootMargin: `${Math.max(1, options.getTriggerMargin())}px`
2491
+ };
2492
+ startElementObserver = intersectionObservers.new(options.onPreviousTriggered, observerOptions);
2493
+ endElementObserver = intersectionObservers.new(options.onNextTriggered, observerOptions);
2494
+ };
2495
+ const enableTriggers = () => {
2496
+ if (triggersEnabled) {
2497
+ disableTriggers();
2498
+ }
2499
+ const startElement = options.getStartElement();
2500
+ const endElement = options.getEndElement();
2501
+ if (startElement && options.shouldFetchPrevious()) {
2502
+ startElementObserver.observe(startElement);
2503
+ }
2504
+ if (endElement && options.shouldFetchNext()) {
2505
+ endElementObserver.observe(endElement);
2506
+ }
2507
+ triggersEnabled = true;
2508
+ };
2509
+ const disableTriggers = () => {
2510
+ if (!triggersEnabled) {
2511
+ return;
2512
+ }
2513
+ startElementObserver.disconnect();
2514
+ endElementObserver.disconnect();
2515
+ triggersEnabled = false;
2516
+ };
2517
+ const refreshTriggers = () => {
2518
+ if (triggersEnabled) {
2519
+ enableTriggers();
2520
+ }
2521
+ };
2522
+ const flushAll = () => {
2523
+ intersectionObservers.flushAll();
2524
+ itemsMutationObserver?.disconnect();
2525
+ };
2526
+ const addedElements = /* @__PURE__ */ new Set();
2527
+ const elementIsUntagged = (element) => !(INFINITE_SCROLL_PAGE_KEY in element.dataset) && !(INFINITE_SCROLL_IGNORE_KEY in element.dataset);
2528
+ const processManuallyAddedElements = () => {
2529
+ Array.from(addedElements).forEach((element) => {
2530
+ if (elementIsUntagged(element)) {
2531
+ element.dataset[INFINITE_SCROLL_IGNORE_KEY] = "true";
2532
+ }
2533
+ itemsObserver.observe(element);
2534
+ });
2535
+ addedElements.clear();
2536
+ };
2537
+ const findUntaggedElements = (containerElement) => {
2538
+ return Array.from(
2539
+ containerElement.querySelectorAll(
2540
+ `:scope > *:not([data-infinite-scroll-page]):not([data-infinite-scroll-ignore])`
2541
+ )
2542
+ );
2543
+ };
2544
+ const processServerLoadedElements = (loadedPage) => {
2545
+ findUntaggedElements(options.getItemsElement()).forEach((element) => {
2546
+ if (elementIsUntagged(element)) {
2547
+ element.dataset[INFINITE_SCROLL_PAGE_KEY] = loadedPage?.toString() || "1";
2548
+ }
2549
+ itemsObserver.observe(element);
2550
+ });
2551
+ };
2552
+ return {
2553
+ setupObservers,
2554
+ enableTriggers,
2555
+ disableTriggers,
2556
+ refreshTriggers,
2557
+ flushAll,
2558
+ processManuallyAddedElements,
2559
+ processServerLoadedElements
2560
+ };
2561
+ };
2562
+
2563
+ // src/infiniteScroll/queryString.ts
2564
+ var useInfiniteScrollQueryString = (options) => {
2565
+ const onItemIntersected = debounce((itemElement) => {
2566
+ if (options.shouldPreserveUrl() || !itemElement) {
2567
+ return;
2568
+ }
2569
+ const pageMap = /* @__PURE__ */ new Map();
2570
+ const elements = [...options.getItemsElement().children];
2571
+ getElementsInViewportFromCollection(itemElement, elements).forEach((element) => {
2572
+ const page2 = getPageFromElement(element) ?? "1";
2573
+ if (pageMap.has(page2)) {
2574
+ pageMap.set(page2, pageMap.get(page2) + 1);
2575
+ } else {
2576
+ pageMap.set(page2, 1);
2577
+ }
2578
+ });
2579
+ const sortedPages = Array.from(pageMap.entries()).sort((a, b) => b[1] - a[1]);
2580
+ const mostVisiblePage = sortedPages[0]?.[0];
2581
+ if (mostVisiblePage === void 0) {
2582
+ return;
2583
+ }
2584
+ const url = new URL(window.location.href);
2585
+ if (mostVisiblePage === "1") {
2586
+ url.searchParams.delete(options.getPageName());
2587
+ } else {
2588
+ url.searchParams.set(options.getPageName(), mostVisiblePage.toString());
2589
+ }
2590
+ router.replace({
2591
+ url: url.toString(),
2592
+ preserveScroll: true,
2593
+ preserveState: true
2594
+ });
2595
+ }, 250);
2596
+ return {
2597
+ onItemIntersected
2598
+ };
2599
+ };
2600
+
2601
+ // src/infiniteScroll/scrollPreservation.ts
2602
+ var useInfiniteScrollPreservation = (options) => {
2603
+ const createCallbacks = () => {
2604
+ let currentScrollTop;
2605
+ let referenceElement = null;
2606
+ let referenceElementTop = 0;
2607
+ const captureScrollPosition = () => {
2608
+ const scrollableContainer = options.getScrollableParent();
2609
+ const itemsElement = options.getItemsElement();
2610
+ currentScrollTop = scrollableContainer?.scrollTop || window.scrollY;
2611
+ const visibleElements = getElementsInViewportFromCollection(
2612
+ itemsElement.firstElementChild,
2613
+ [...itemsElement.children]
2614
+ );
2615
+ if (visibleElements.length > 0) {
2616
+ referenceElement = visibleElements[0];
2617
+ const containerRect = scrollableContainer?.getBoundingClientRect() || { top: 0 };
2618
+ const containerTop = scrollableContainer ? containerRect.top : 0;
2619
+ const rect = referenceElement.getBoundingClientRect();
2620
+ referenceElementTop = rect.top - containerTop;
2621
+ }
2622
+ };
2623
+ const restoreScrollPosition = () => {
2624
+ if (!referenceElement) {
2625
+ return;
2626
+ }
2627
+ let attempts = 0;
2628
+ let restored = false;
2629
+ const restore = () => {
2630
+ attempts++;
2631
+ if (restored || attempts > 10) {
2632
+ return false;
2633
+ }
2634
+ const scrollableContainer = options.getScrollableParent();
2635
+ const containerRect = scrollableContainer?.getBoundingClientRect() || { top: 0 };
2636
+ const containerTop = scrollableContainer ? containerRect.top : 0;
2637
+ const newRect = referenceElement.getBoundingClientRect();
2638
+ const newElementTop = newRect.top - containerTop;
2639
+ const adjustment = newElementTop - referenceElementTop;
2640
+ if (adjustment === 0) {
2641
+ window.requestAnimationFrame(restore);
2642
+ return;
2643
+ }
2644
+ if (scrollableContainer) {
2645
+ scrollableContainer.scrollTo({ top: currentScrollTop + adjustment });
2646
+ } else {
2647
+ window.scrollTo(0, window.scrollY + adjustment);
2648
+ }
2649
+ restored = true;
2650
+ };
2651
+ restore();
2652
+ };
2653
+ return {
2654
+ captureScrollPosition,
2655
+ restoreScrollPosition
2656
+ };
2657
+ };
2658
+ return {
2659
+ createCallbacks
2660
+ };
2661
+ };
2662
+
2663
+ // src/infiniteScroll.ts
2664
+ function useInfiniteScroll(options) {
2665
+ const queryStringManager = useInfiniteScrollQueryString({ ...options, getPageName: () => dataManager.getPageName() });
2666
+ const scrollPreservation = useInfiniteScrollPreservation(options);
2667
+ const elementManager = useInfiniteScrollElementManager({
2668
+ ...options,
2669
+ // As items enter viewport, update URL to reflect the most visible page
2670
+ onItemIntersected: queryStringManager.onItemIntersected,
2671
+ onPreviousTriggered: () => dataManager.fetchPrevious(),
2672
+ onNextTriggered: () => dataManager.fetchNext()
2673
+ });
2674
+ const dataManager = useInfiniteScrollData({
2675
+ ...options,
2676
+ // Before updating page data, tag any manually added DOM elements
2677
+ // so they don't get confused with server-loaded content
2678
+ onBeforeUpdate: elementManager.processManuallyAddedElements,
2679
+ // After successful request, tag new server content
2680
+ onCompletePreviousRequest: (loadedPage) => {
2681
+ setTimeout(() => {
2682
+ elementManager.processServerLoadedElements(loadedPage);
2683
+ options.onCompletePreviousRequest();
2684
+ window.queueMicrotask(elementManager.refreshTriggers);
2685
+ });
2686
+ },
2687
+ onCompleteNextRequest: (loadedPage) => {
2688
+ setTimeout(() => {
2689
+ elementManager.processServerLoadedElements(loadedPage);
2690
+ options.onCompleteNextRequest();
2691
+ window.queueMicrotask(elementManager.refreshTriggers);
2692
+ });
2693
+ }
2694
+ });
2695
+ const addScrollPreservationCallbacks = (reloadOptions) => {
2696
+ const { captureScrollPosition, restoreScrollPosition } = scrollPreservation.createCallbacks();
2697
+ const originalOnBeforeUpdate = reloadOptions.onBeforeUpdate || (() => {
2698
+ });
2699
+ const originalOnSuccess = reloadOptions.onSuccess || (() => {
2700
+ });
2701
+ reloadOptions.onBeforeUpdate = (page2) => {
2702
+ originalOnBeforeUpdate(page2);
2703
+ captureScrollPosition();
2704
+ };
2705
+ reloadOptions.onSuccess = (page2) => {
2706
+ originalOnSuccess(page2);
2707
+ restoreScrollPosition();
2708
+ };
2709
+ return reloadOptions;
2710
+ };
2711
+ const originalFetchNext = dataManager.fetchNext;
2712
+ dataManager.fetchNext = (reloadOptions = {}) => {
2713
+ if (options.inReverseMode()) {
2714
+ reloadOptions = addScrollPreservationCallbacks(reloadOptions);
2715
+ }
2716
+ originalFetchNext(reloadOptions);
2717
+ };
2718
+ const originalFetchPrevious = dataManager.fetchPrevious;
2719
+ dataManager.fetchPrevious = (reloadOptions = {}) => {
2720
+ if (!options.inReverseMode()) {
2721
+ reloadOptions = addScrollPreservationCallbacks(reloadOptions);
2722
+ }
2723
+ originalFetchPrevious(reloadOptions);
2724
+ };
2725
+ return {
2726
+ dataManager,
2727
+ elementManager
2728
+ };
2729
+ }
2730
+
2238
2731
  // src/navigationEvents.ts
2239
2732
  function shouldIntercept(event) {
2240
2733
  const isLink = event.currentTarget.tagName.toLowerCase() === "a";
@@ -2280,7 +2773,7 @@ var configure = (options) => {
2280
2773
  progress2.id = baseComponentSelector;
2281
2774
  progress2.innerHTML = settings.template;
2282
2775
  };
2283
- var set2 = (n) => {
2776
+ var set4 = (n) => {
2284
2777
  const started = isStarted();
2285
2778
  n = clamp(n, settings.minimum, 1);
2286
2779
  status = n === 1 ? null : n;
@@ -2329,7 +2822,7 @@ var set2 = (n) => {
2329
2822
  var isStarted = () => typeof status === "number";
2330
2823
  var start = () => {
2331
2824
  if (!status) {
2332
- set2(0);
2825
+ set4(0);
2333
2826
  }
2334
2827
  const work = function() {
2335
2828
  setTimeout(function() {
@@ -2349,7 +2842,7 @@ var done = (force) => {
2349
2842
  return;
2350
2843
  }
2351
2844
  increaseByRandom(0.3 + 0.5 * Math.random());
2352
- set2(1);
2845
+ set4(1);
2353
2846
  };
2354
2847
  var increaseByRandom = (amount) => {
2355
2848
  const n = status;
@@ -2373,7 +2866,7 @@ var increaseByRandom = (amount) => {
2373
2866
  }
2374
2867
  return 0;
2375
2868
  })();
2376
- return set2(clamp(n + amount, 0, 0.994));
2869
+ return set4(clamp(n + amount, 0, 0.994));
2377
2870
  };
2378
2871
  var render = (fromStart) => {
2379
2872
  if (isRendered()) {
@@ -2519,7 +3012,7 @@ var progress_component_default = {
2519
3012
  configure,
2520
3013
  isStarted,
2521
3014
  done,
2522
- set: set2,
3015
+ set: set4,
2523
3016
  remove,
2524
3017
  start,
2525
3018
  status,
@@ -2746,6 +3239,7 @@ var router = new Router();
2746
3239
  export {
2747
3240
  createHeadManager,
2748
3241
  formDataToObject,
3242
+ getScrollableParent,
2749
3243
  hide2 as hideProgress,
2750
3244
  hrefToUrl,
2751
3245
  isUrlMethodPair,
@@ -2758,7 +3252,8 @@ export {
2758
3252
  setupProgress,
2759
3253
  shouldIntercept,
2760
3254
  shouldNavigate,
2761
- urlWithoutHash
3255
+ urlWithoutHash,
3256
+ useInfiniteScroll
2762
3257
  };
2763
3258
  /* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
2764
3259
  * @license MIT */