@inertiajs/core 2.1.11 → 2.2.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/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
  };
@@ -692,6 +698,11 @@ var History = class {
692
698
  this.replaceState(this.current);
693
699
  }
694
700
  }
701
+ clearInitialState(key) {
702
+ if (this.initialState && this.initialState[key] !== void 0) {
703
+ delete this.initialState[key];
704
+ }
705
+ }
695
706
  hasAnyState() {
696
707
  return !!this.getAllState();
697
708
  }
@@ -821,6 +832,7 @@ var InitialVisit = class {
821
832
  static clearRememberedStateOnReload() {
822
833
  if (navigationType.isReload()) {
823
834
  history.deleteState(history.rememberedState);
835
+ history.clearInitialState(history.rememberedState);
824
836
  }
825
837
  }
826
838
  static handleBackForward() {
@@ -1188,6 +1200,7 @@ var PrefetchedRequests = class {
1188
1200
  "replace",
1189
1201
  "prefetch",
1190
1202
  "onBefore",
1203
+ "onBeforeUpdate",
1191
1204
  "onStart",
1192
1205
  "onProgress",
1193
1206
  "onFinish",
@@ -1216,6 +1229,7 @@ var RequestParams = class _RequestParams {
1216
1229
  } else {
1217
1230
  const wrappedCallbacks = {
1218
1231
  onBefore: this.wrapCallback(params, "onBefore"),
1232
+ onBeforeUpdate: this.wrapCallback(params, "onBeforeUpdate"),
1219
1233
  onStart: this.wrapCallback(params, "onStart"),
1220
1234
  onProgress: this.wrapCallback(params, "onProgress"),
1221
1235
  onFinish: this.wrapCallback(params, "onFinish"),
@@ -1346,6 +1360,9 @@ var RequestParams = class _RequestParams {
1346
1360
  }
1347
1361
  };
1348
1362
 
1363
+ // src/response.ts
1364
+ import { get, set } from "lodash-es";
1365
+
1349
1366
  // src/modal.ts
1350
1367
  var modal_default = {
1351
1368
  modal: null,
@@ -1508,6 +1525,8 @@ var Response = class _Response {
1508
1525
  await this.setRememberedState(pageResponse);
1509
1526
  this.requestParams.setPreserveOptions(pageResponse);
1510
1527
  pageResponse.url = history.preserveUrl ? page.get().url : this.pageUrl(pageResponse);
1528
+ this.requestParams.all().onBeforeUpdate(pageResponse);
1529
+ fireBeforeUpdateEvent(pageResponse);
1511
1530
  return page.set(pageResponse, {
1512
1531
  replace: this.requestParams.all().replace,
1513
1532
  preserveScroll: this.requestParams.all().preserveScroll,
@@ -1547,36 +1566,43 @@ var Response = class _Response {
1547
1566
  if (!this.requestParams.isPartial() || pageResponse.component !== page.get().component) {
1548
1567
  return;
1549
1568
  }
1550
- const propsToMerge = pageResponse.mergeProps || [];
1569
+ const propsToAppend = pageResponse.mergeProps || [];
1570
+ const propsToPrepend = pageResponse.prependProps || [];
1551
1571
  const propsToDeepMerge = pageResponse.deepMergeProps || [];
1552
1572
  const matchPropsOn = pageResponse.matchPropsOn || [];
1553
- propsToMerge.forEach((prop) => {
1554
- const incomingProp = pageResponse.props[prop];
1573
+ const mergeProp = (prop, shouldAppend) => {
1574
+ const currentProp = get(page.get().props, prop);
1575
+ const incomingProp = get(pageResponse.props, prop);
1555
1576
  if (Array.isArray(incomingProp)) {
1556
- pageResponse.props[prop] = this.mergeOrMatchItems(
1557
- page.get().props[prop] || [],
1577
+ const newArray = this.mergeOrMatchItems(
1578
+ currentProp || [],
1558
1579
  incomingProp,
1559
1580
  prop,
1560
- matchPropsOn
1581
+ matchPropsOn,
1582
+ shouldAppend
1561
1583
  );
1584
+ set(pageResponse.props, prop, newArray);
1562
1585
  } else if (typeof incomingProp === "object" && incomingProp !== null) {
1563
- pageResponse.props[prop] = {
1564
- ...page.get().props[prop] || [],
1586
+ const newObject = {
1587
+ ...currentProp || {},
1565
1588
  ...incomingProp
1566
1589
  };
1590
+ set(pageResponse.props, prop, newObject);
1567
1591
  }
1568
- });
1592
+ };
1593
+ propsToAppend.forEach((prop) => mergeProp(prop, true));
1594
+ propsToPrepend.forEach((prop) => mergeProp(prop, false));
1569
1595
  propsToDeepMerge.forEach((prop) => {
1570
- const incomingProp = pageResponse.props[prop];
1571
1596
  const currentProp = page.get().props[prop];
1572
- const deepMerge = (target, source, currentKey) => {
1597
+ const incomingProp = pageResponse.props[prop];
1598
+ const deepMerge = (target, source, matchProp) => {
1573
1599
  if (Array.isArray(source)) {
1574
- return this.mergeOrMatchItems(target, source, currentKey, matchPropsOn);
1600
+ return this.mergeOrMatchItems(target, source, matchProp, matchPropsOn);
1575
1601
  }
1576
1602
  if (typeof source === "object" && source !== null) {
1577
1603
  return Object.keys(source).reduce(
1578
1604
  (acc, key) => {
1579
- acc[key] = deepMerge(target ? target[key] : void 0, source[key], `${currentKey}.${key}`);
1605
+ acc[key] = deepMerge(target ? target[key] : void 0, source[key], `${matchProp}.${key}`);
1580
1606
  return acc;
1581
1607
  },
1582
1608
  { ...target }
@@ -1588,32 +1614,52 @@ var Response = class _Response {
1588
1614
  });
1589
1615
  pageResponse.props = { ...page.get().props, ...pageResponse.props };
1590
1616
  }
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;
1617
+ mergeOrMatchItems(existingItems, newItems, matchProp, matchPropsOn, shouldAppend = true) {
1618
+ const items = Array.isArray(existingItems) ? existingItems : [];
1619
+ const matchingKey = matchPropsOn.find((key) => {
1620
+ const keyPath = key.split(".").slice(0, -1).join(".");
1621
+ return keyPath === matchProp;
1595
1622
  });
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);
1623
+ if (!matchingKey) {
1624
+ return shouldAppend ? [...items, ...newItems] : [...newItems, ...items];
1625
+ }
1626
+ const uniqueProperty = matchingKey.split(".").pop() || "";
1627
+ const newItemsMap = /* @__PURE__ */ new Map();
1628
+ newItems.forEach((item) => {
1629
+ if (this.hasUniqueProperty(item, uniqueProperty)) {
1630
+ newItemsMap.set(item[uniqueProperty], item);
1607
1631
  }
1608
1632
  });
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);
1633
+ return shouldAppend ? this.appendWithMatching(items, newItems, newItemsMap, uniqueProperty) : this.prependWithMatching(items, newItems, newItemsMap, uniqueProperty);
1634
+ }
1635
+ appendWithMatching(existingItems, newItems, newItemsMap, uniqueProperty) {
1636
+ const updatedExisting = existingItems.map((item) => {
1637
+ if (this.hasUniqueProperty(item, uniqueProperty) && newItemsMap.has(item[uniqueProperty])) {
1638
+ return newItemsMap.get(item[uniqueProperty]);
1639
+ }
1640
+ return item;
1641
+ });
1642
+ const newItemsToAdd = newItems.filter((item) => {
1643
+ if (!this.hasUniqueProperty(item, uniqueProperty)) {
1644
+ return true;
1645
+ }
1646
+ return !existingItems.some(
1647
+ (existing) => this.hasUniqueProperty(existing, uniqueProperty) && existing[uniqueProperty] === item[uniqueProperty]
1648
+ );
1649
+ });
1650
+ return [...updatedExisting, ...newItemsToAdd];
1651
+ }
1652
+ prependWithMatching(existingItems, newItems, newItemsMap, uniqueProperty) {
1653
+ const untouchedExisting = existingItems.filter((item) => {
1654
+ if (this.hasUniqueProperty(item, uniqueProperty)) {
1655
+ return !newItemsMap.has(item[uniqueProperty]);
1614
1656
  }
1657
+ return true;
1615
1658
  });
1616
- return Array.from(map.values());
1659
+ return [...newItems, ...untouchedExisting];
1660
+ }
1661
+ hasUniqueProperty(item, property) {
1662
+ return item && typeof item === "object" && property in item;
1617
1663
  }
1618
1664
  async setRememberedState(pageResponse) {
1619
1665
  const rememberedState = await history.getState(history.rememberedState, {});
@@ -1955,6 +2001,43 @@ var Router = class {
1955
2001
  replace(params) {
1956
2002
  this.clientVisit(params, { replace: true });
1957
2003
  }
2004
+ replaceProp(name, value, options) {
2005
+ this.replace({
2006
+ preserveScroll: true,
2007
+ preserveState: true,
2008
+ props(currentProps) {
2009
+ const newValue = typeof value === "function" ? value(get2(currentProps, name), currentProps) : value;
2010
+ return set2(cloneDeep2(currentProps), name, newValue);
2011
+ },
2012
+ ...options || {}
2013
+ });
2014
+ }
2015
+ appendToProp(name, value, options) {
2016
+ this.replaceProp(
2017
+ name,
2018
+ (currentValue, currentProps) => {
2019
+ const newValue = typeof value === "function" ? value(currentValue, currentProps) : value;
2020
+ if (!Array.isArray(currentValue)) {
2021
+ currentValue = currentValue !== void 0 ? [currentValue] : [];
2022
+ }
2023
+ return [...currentValue, newValue];
2024
+ },
2025
+ options
2026
+ );
2027
+ }
2028
+ prependToProp(name, value, options) {
2029
+ this.replaceProp(
2030
+ name,
2031
+ (currentValue, currentProps) => {
2032
+ const newValue = typeof value === "function" ? value(currentValue, currentProps) : value;
2033
+ if (!Array.isArray(currentValue)) {
2034
+ currentValue = currentValue !== void 0 ? [currentValue] : [];
2035
+ }
2036
+ return [newValue, ...currentValue];
2037
+ },
2038
+ options
2039
+ );
2040
+ }
1958
2041
  push(params) {
1959
2042
  this.clientVisit(params);
1960
2043
  }
@@ -2047,6 +2130,8 @@ var Router = class {
2047
2130
  }),
2048
2131
  onBefore: options.onBefore || (() => {
2049
2132
  }),
2133
+ onBeforeUpdate: options.onBeforeUpdate || (() => {
2134
+ }),
2050
2135
  onStart: options.onStart || (() => {
2051
2136
  }),
2052
2137
  onProgress: options.onProgress || (() => {
@@ -2074,8 +2159,48 @@ var Router = class {
2074
2159
  }
2075
2160
  };
2076
2161
 
2162
+ // src/domUtils.ts
2163
+ var elementInViewport = (el) => {
2164
+ const rect = el.getBoundingClientRect();
2165
+ const verticallyVisible = rect.top < window.innerHeight && rect.bottom >= 0;
2166
+ const horizontallyVisible = rect.left < window.innerWidth && rect.right >= 0;
2167
+ return verticallyVisible && horizontallyVisible;
2168
+ };
2169
+ var getScrollableParent = (element) => {
2170
+ let parent = element?.parentElement;
2171
+ while (parent) {
2172
+ const overflowY = window.getComputedStyle(parent).overflowY;
2173
+ if (overflowY === "auto" || overflowY === "scroll") {
2174
+ return parent;
2175
+ }
2176
+ parent = parent.parentElement;
2177
+ }
2178
+ return null;
2179
+ };
2180
+ var getElementsInViewportFromCollection = (referenceElement, elements) => {
2181
+ const referenceIndex = elements.indexOf(referenceElement);
2182
+ const visibleElements = [];
2183
+ for (let i = referenceIndex; i >= 0; i--) {
2184
+ const element = elements[i];
2185
+ if (elementInViewport(element)) {
2186
+ visibleElements.push(element);
2187
+ } else {
2188
+ break;
2189
+ }
2190
+ }
2191
+ for (let i = referenceIndex + 1; i < elements.length; i++) {
2192
+ const element = elements[i];
2193
+ if (elementInViewport(element)) {
2194
+ visibleElements.push(element);
2195
+ } else {
2196
+ break;
2197
+ }
2198
+ }
2199
+ return visibleElements;
2200
+ };
2201
+
2077
2202
  // src/formObject.ts
2078
- import { get, set } from "lodash-es";
2203
+ import { get as get3, set as set3 } from "lodash-es";
2079
2204
  function undotKey(key) {
2080
2205
  if (!key.includes(".")) {
2081
2206
  return key;
@@ -2110,15 +2235,15 @@ function formDataToObject(source) {
2110
2235
  const path = parseKey(undotKey(key));
2111
2236
  if (path[path.length - 1] === "") {
2112
2237
  const arrayPath = path.slice(0, -1);
2113
- const existing = get(form, arrayPath);
2238
+ const existing = get3(form, arrayPath);
2114
2239
  if (Array.isArray(existing)) {
2115
2240
  existing.push(value);
2116
2241
  } else {
2117
- set(form, arrayPath, [value]);
2242
+ set3(form, arrayPath, [value]);
2118
2243
  }
2119
2244
  continue;
2120
2245
  }
2121
- set(form, path, value);
2246
+ set3(form, path, value);
2122
2247
  }
2123
2248
  return form;
2124
2249
  }
@@ -2235,6 +2360,463 @@ function createHeadManager(isServer2, titleCallback, onUpdate) {
2235
2360
  };
2236
2361
  }
2237
2362
 
2363
+ // src/infiniteScroll/data.ts
2364
+ var MERGE_INTENT_HEADER = "X-Inertia-Infinite-Scroll-Merge-Intent";
2365
+ var useInfiniteScrollData = (options) => {
2366
+ const getScrollPropFromCurrentPage = () => {
2367
+ const scrollProp = page.get().scrollProps?.[options.getPropName()];
2368
+ if (scrollProp) {
2369
+ return scrollProp;
2370
+ }
2371
+ throw new Error(`The page object does not contain a scroll prop named "${options.getPropName()}".`);
2372
+ };
2373
+ const { previousPage, nextPage, currentPage: lastLoadedPage } = getScrollPropFromCurrentPage();
2374
+ const state = {
2375
+ loading: false,
2376
+ previousPage,
2377
+ nextPage,
2378
+ lastLoadedPage,
2379
+ requestCount: 0
2380
+ };
2381
+ const getRememberKey = () => `inertia:infinite-scroll-data:${options.getPropName()}`;
2382
+ const rememberedState = router.restore(getRememberKey());
2383
+ if (rememberedState && typeof rememberedState === "object") {
2384
+ state.previousPage = rememberedState.previousPage;
2385
+ state.nextPage = rememberedState.nextPage;
2386
+ state.lastLoadedPage = rememberedState.lastLoadedPage;
2387
+ state.requestCount = rememberedState.requestCount || 0;
2388
+ }
2389
+ const getScrollPropKeyForSide = (side) => {
2390
+ return side === "next" ? "nextPage" : "previousPage";
2391
+ };
2392
+ const findPageToLoad = (side) => {
2393
+ const pagePropName = getScrollPropKeyForSide(side);
2394
+ return state[pagePropName];
2395
+ };
2396
+ const syncStateOnSuccess = (side) => {
2397
+ const scrollProp = getScrollPropFromCurrentPage();
2398
+ const paginationProp = getScrollPropKeyForSide(side);
2399
+ state.lastLoadedPage = scrollProp.currentPage;
2400
+ state[paginationProp] = scrollProp[paginationProp];
2401
+ state.requestCount += 1;
2402
+ router.remember(
2403
+ {
2404
+ previousPage: state.previousPage,
2405
+ nextPage: state.nextPage,
2406
+ lastLoadedPage: state.lastLoadedPage,
2407
+ requestCount: state.requestCount
2408
+ },
2409
+ getRememberKey()
2410
+ );
2411
+ };
2412
+ const getPageName = () => getScrollPropFromCurrentPage().pageName;
2413
+ const getRequestCount = () => state.requestCount;
2414
+ const fetchPage = (side, reloadOptions = {}) => {
2415
+ const page2 = findPageToLoad(side);
2416
+ if (state.loading || page2 === null) {
2417
+ return;
2418
+ }
2419
+ state.loading = true;
2420
+ router.reload({
2421
+ ...reloadOptions,
2422
+ data: { [getPageName()]: page2 },
2423
+ only: [options.getPropName()],
2424
+ preserveUrl: true,
2425
+ // we handle URL updates manually via useInfiniteScrollQueryString()
2426
+ headers: {
2427
+ [MERGE_INTENT_HEADER]: side === "previous" ? "prepend" : "append",
2428
+ ...reloadOptions.headers
2429
+ },
2430
+ onBefore: (visit) => {
2431
+ side === "next" ? options.onBeforeNextRequest() : options.onBeforePreviousRequest();
2432
+ reloadOptions.onBefore?.(visit);
2433
+ },
2434
+ onBeforeUpdate: (page3) => {
2435
+ options.onBeforeUpdate();
2436
+ reloadOptions.onBeforeUpdate?.(page3);
2437
+ },
2438
+ onSuccess: (page3) => {
2439
+ syncStateOnSuccess(side);
2440
+ reloadOptions.onSuccess?.(page3);
2441
+ },
2442
+ onFinish: (visit) => {
2443
+ state.loading = false;
2444
+ side === "next" ? options.onCompleteNextRequest(state.lastLoadedPage) : options.onCompletePreviousRequest(state.lastLoadedPage);
2445
+ reloadOptions.onFinish?.(visit);
2446
+ }
2447
+ });
2448
+ };
2449
+ const getLastLoadedPage = () => state.lastLoadedPage;
2450
+ const hasPrevious = () => !!state.previousPage;
2451
+ const hasNext = () => !!state.nextPage;
2452
+ const fetchPrevious = (reloadOptions) => fetchPage("previous", reloadOptions);
2453
+ const fetchNext = (reloadOptions) => fetchPage("next", reloadOptions);
2454
+ return {
2455
+ getLastLoadedPage,
2456
+ getPageName,
2457
+ getRequestCount,
2458
+ hasPrevious,
2459
+ hasNext,
2460
+ fetchNext,
2461
+ fetchPrevious
2462
+ };
2463
+ };
2464
+
2465
+ // src/intersectionObservers.ts
2466
+ var useIntersectionObservers = () => {
2467
+ const intersectionObservers = [];
2468
+ const newIntersectionObserver = (callback, options = {}) => {
2469
+ const observer = new IntersectionObserver((entries) => {
2470
+ for (const entry of entries) {
2471
+ if (entry.isIntersecting) {
2472
+ callback(entry);
2473
+ }
2474
+ }
2475
+ }, options);
2476
+ intersectionObservers.push(observer);
2477
+ return observer;
2478
+ };
2479
+ const flushAll = () => {
2480
+ intersectionObservers.forEach((observer) => observer.disconnect());
2481
+ intersectionObservers.length = 0;
2482
+ };
2483
+ return {
2484
+ new: newIntersectionObserver,
2485
+ flushAll
2486
+ };
2487
+ };
2488
+
2489
+ // src/infiniteScroll/elements.ts
2490
+ var INFINITE_SCROLL_PAGE_KEY = "infiniteScrollPage";
2491
+ var INFINITE_SCROLL_IGNORE_KEY = "infiniteScrollIgnore";
2492
+ var getPageFromElement = (element) => element.dataset[INFINITE_SCROLL_PAGE_KEY];
2493
+ var useInfiniteScrollElementManager = (options) => {
2494
+ const intersectionObservers = useIntersectionObservers();
2495
+ let itemsObserver;
2496
+ let startElementObserver;
2497
+ let endElementObserver;
2498
+ let itemsMutationObserver;
2499
+ let triggersEnabled = false;
2500
+ const setupObservers = () => {
2501
+ itemsMutationObserver = new MutationObserver((mutations) => {
2502
+ mutations.forEach((mutation) => {
2503
+ mutation.addedNodes.forEach((node) => {
2504
+ if (node.nodeType !== Node.ELEMENT_NODE) {
2505
+ return;
2506
+ }
2507
+ addedElements.add(node);
2508
+ });
2509
+ });
2510
+ rememberElementsDebounced();
2511
+ });
2512
+ itemsMutationObserver.observe(options.getItemsElement(), { childList: true });
2513
+ itemsObserver = intersectionObservers.new(
2514
+ (entry) => options.onItemIntersected(entry.target),
2515
+ { threshold: 0 }
2516
+ );
2517
+ const observerOptions = {
2518
+ root: options.getScrollableParent(),
2519
+ rootMargin: `${Math.max(1, options.getTriggerMargin())}px`
2520
+ };
2521
+ startElementObserver = intersectionObservers.new(options.onPreviousTriggered, observerOptions);
2522
+ endElementObserver = intersectionObservers.new(options.onNextTriggered, observerOptions);
2523
+ };
2524
+ const enableTriggers = () => {
2525
+ if (triggersEnabled) {
2526
+ disableTriggers();
2527
+ }
2528
+ const startElement = options.getStartElement();
2529
+ const endElement = options.getEndElement();
2530
+ if (startElement && options.shouldFetchPrevious()) {
2531
+ startElementObserver.observe(startElement);
2532
+ }
2533
+ if (endElement && options.shouldFetchNext()) {
2534
+ endElementObserver.observe(endElement);
2535
+ }
2536
+ triggersEnabled = true;
2537
+ };
2538
+ const disableTriggers = () => {
2539
+ if (!triggersEnabled) {
2540
+ return;
2541
+ }
2542
+ startElementObserver.disconnect();
2543
+ endElementObserver.disconnect();
2544
+ triggersEnabled = false;
2545
+ };
2546
+ const refreshTriggers = () => {
2547
+ if (triggersEnabled) {
2548
+ enableTriggers();
2549
+ }
2550
+ };
2551
+ const flushAll = () => {
2552
+ intersectionObservers.flushAll();
2553
+ itemsMutationObserver?.disconnect();
2554
+ };
2555
+ const addedElements = /* @__PURE__ */ new Set();
2556
+ const elementIsUntagged = (element) => !(INFINITE_SCROLL_PAGE_KEY in element.dataset) && !(INFINITE_SCROLL_IGNORE_KEY in element.dataset);
2557
+ const processManuallyAddedElements = () => {
2558
+ Array.from(addedElements).forEach((element) => {
2559
+ if (elementIsUntagged(element)) {
2560
+ element.dataset[INFINITE_SCROLL_IGNORE_KEY] = "true";
2561
+ }
2562
+ itemsObserver.observe(element);
2563
+ });
2564
+ addedElements.clear();
2565
+ };
2566
+ const findUntaggedElements = (containerElement) => {
2567
+ return Array.from(
2568
+ containerElement.querySelectorAll(
2569
+ `:scope > *:not([data-infinite-scroll-page]):not([data-infinite-scroll-ignore])`
2570
+ )
2571
+ );
2572
+ };
2573
+ let hasRestoredElements = false;
2574
+ const processServerLoadedElements = (loadedPage) => {
2575
+ if (!hasRestoredElements) {
2576
+ hasRestoredElements = true;
2577
+ if (restoreElements()) {
2578
+ return;
2579
+ }
2580
+ }
2581
+ findUntaggedElements(options.getItemsElement()).forEach((element) => {
2582
+ if (elementIsUntagged(element)) {
2583
+ element.dataset[INFINITE_SCROLL_PAGE_KEY] = loadedPage?.toString() || "1";
2584
+ }
2585
+ itemsObserver.observe(element);
2586
+ });
2587
+ rememberElements();
2588
+ };
2589
+ const getElementsRememberKey = () => `inertia:infinite-scroll-elements:${options.getPropName()}`;
2590
+ const rememberElements = () => {
2591
+ const pageElementRange = {};
2592
+ const childNodes = options.getItemsElement().childNodes;
2593
+ for (let index = 0; index < childNodes.length; index++) {
2594
+ const node = childNodes[index];
2595
+ if (node.nodeType !== Node.ELEMENT_NODE) {
2596
+ continue;
2597
+ }
2598
+ const page2 = getPageFromElement(node);
2599
+ if (typeof page2 === "undefined") {
2600
+ continue;
2601
+ }
2602
+ if (!(page2 in pageElementRange)) {
2603
+ pageElementRange[page2] = { from: index, to: index };
2604
+ } else {
2605
+ pageElementRange[page2].to = index;
2606
+ }
2607
+ }
2608
+ router.remember(pageElementRange, getElementsRememberKey());
2609
+ };
2610
+ const rememberElementsDebounced = debounce(rememberElements, 250);
2611
+ const restoreElements = () => {
2612
+ const pageElementRange = router.restore(getElementsRememberKey());
2613
+ if (!pageElementRange || typeof pageElementRange !== "object") {
2614
+ return false;
2615
+ }
2616
+ const childNodes = options.getItemsElement().childNodes;
2617
+ for (let index = 0; index < childNodes.length; index++) {
2618
+ const node = childNodes[index];
2619
+ if (node.nodeType !== Node.ELEMENT_NODE) {
2620
+ continue;
2621
+ }
2622
+ const element = node;
2623
+ let elementPage;
2624
+ for (const [page2, range] of Object.entries(pageElementRange)) {
2625
+ if (index >= range.from && index <= range.to) {
2626
+ elementPage = page2;
2627
+ break;
2628
+ }
2629
+ }
2630
+ if (elementPage) {
2631
+ element.dataset[INFINITE_SCROLL_PAGE_KEY] = elementPage;
2632
+ } else if (!elementIsUntagged(element)) {
2633
+ continue;
2634
+ } else {
2635
+ element.dataset[INFINITE_SCROLL_IGNORE_KEY] = "true";
2636
+ }
2637
+ itemsObserver.observe(element);
2638
+ }
2639
+ return true;
2640
+ };
2641
+ return {
2642
+ setupObservers,
2643
+ enableTriggers,
2644
+ disableTriggers,
2645
+ refreshTriggers,
2646
+ flushAll,
2647
+ processManuallyAddedElements,
2648
+ processServerLoadedElements
2649
+ };
2650
+ };
2651
+
2652
+ // src/infiniteScroll/queryString.ts
2653
+ var useInfiniteScrollQueryString = (options) => {
2654
+ const onItemIntersected = debounce((itemElement) => {
2655
+ if (options.shouldPreserveUrl() || !itemElement) {
2656
+ return;
2657
+ }
2658
+ const pageMap = /* @__PURE__ */ new Map();
2659
+ const elements = [...options.getItemsElement().children];
2660
+ getElementsInViewportFromCollection(itemElement, elements).forEach((element) => {
2661
+ const page2 = getPageFromElement(element) ?? "1";
2662
+ if (pageMap.has(page2)) {
2663
+ pageMap.set(page2, pageMap.get(page2) + 1);
2664
+ } else {
2665
+ pageMap.set(page2, 1);
2666
+ }
2667
+ });
2668
+ const sortedPages = Array.from(pageMap.entries()).sort((a, b) => b[1] - a[1]);
2669
+ const mostVisiblePage = sortedPages[0]?.[0];
2670
+ if (mostVisiblePage === void 0) {
2671
+ return;
2672
+ }
2673
+ const url = new URL(window.location.href);
2674
+ if (mostVisiblePage === "1") {
2675
+ url.searchParams.delete(options.getPageName());
2676
+ } else {
2677
+ url.searchParams.set(options.getPageName(), mostVisiblePage.toString());
2678
+ }
2679
+ router.replace({
2680
+ url: url.toString(),
2681
+ preserveScroll: true,
2682
+ preserveState: true
2683
+ });
2684
+ }, 250);
2685
+ return {
2686
+ onItemIntersected
2687
+ };
2688
+ };
2689
+
2690
+ // src/infiniteScroll/scrollPreservation.ts
2691
+ var useInfiniteScrollPreservation = (options) => {
2692
+ const createCallbacks = () => {
2693
+ let currentScrollTop;
2694
+ let referenceElement = null;
2695
+ let referenceElementTop = 0;
2696
+ const captureScrollPosition = () => {
2697
+ const scrollableContainer = options.getScrollableParent();
2698
+ const itemsElement = options.getItemsElement();
2699
+ currentScrollTop = scrollableContainer?.scrollTop || window.scrollY;
2700
+ const visibleElements = getElementsInViewportFromCollection(
2701
+ itemsElement.firstElementChild,
2702
+ [...itemsElement.children]
2703
+ );
2704
+ if (visibleElements.length > 0) {
2705
+ referenceElement = visibleElements[0];
2706
+ const containerRect = scrollableContainer?.getBoundingClientRect() || { top: 0 };
2707
+ const containerTop = scrollableContainer ? containerRect.top : 0;
2708
+ const rect = referenceElement.getBoundingClientRect();
2709
+ referenceElementTop = rect.top - containerTop;
2710
+ }
2711
+ };
2712
+ const restoreScrollPosition = () => {
2713
+ if (!referenceElement) {
2714
+ return;
2715
+ }
2716
+ let attempts = 0;
2717
+ let restored = false;
2718
+ const restore = () => {
2719
+ attempts++;
2720
+ if (restored || attempts > 10) {
2721
+ return false;
2722
+ }
2723
+ const scrollableContainer = options.getScrollableParent();
2724
+ const containerRect = scrollableContainer?.getBoundingClientRect() || { top: 0 };
2725
+ const containerTop = scrollableContainer ? containerRect.top : 0;
2726
+ const newRect = referenceElement.getBoundingClientRect();
2727
+ const newElementTop = newRect.top - containerTop;
2728
+ const adjustment = newElementTop - referenceElementTop;
2729
+ if (adjustment === 0) {
2730
+ window.requestAnimationFrame(restore);
2731
+ return;
2732
+ }
2733
+ if (scrollableContainer) {
2734
+ scrollableContainer.scrollTo({ top: currentScrollTop + adjustment });
2735
+ } else {
2736
+ window.scrollTo(0, window.scrollY + adjustment);
2737
+ }
2738
+ restored = true;
2739
+ };
2740
+ restore();
2741
+ };
2742
+ return {
2743
+ captureScrollPosition,
2744
+ restoreScrollPosition
2745
+ };
2746
+ };
2747
+ return {
2748
+ createCallbacks
2749
+ };
2750
+ };
2751
+
2752
+ // src/infiniteScroll.ts
2753
+ function useInfiniteScroll(options) {
2754
+ const queryStringManager = useInfiniteScrollQueryString({ ...options, getPageName: () => dataManager.getPageName() });
2755
+ const scrollPreservation = useInfiniteScrollPreservation(options);
2756
+ const elementManager = useInfiniteScrollElementManager({
2757
+ ...options,
2758
+ // As items enter viewport, update URL to reflect the most visible page
2759
+ onItemIntersected: queryStringManager.onItemIntersected,
2760
+ onPreviousTriggered: () => dataManager.fetchPrevious(),
2761
+ onNextTriggered: () => dataManager.fetchNext()
2762
+ });
2763
+ const dataManager = useInfiniteScrollData({
2764
+ ...options,
2765
+ // Before updating page data, tag any manually added DOM elements
2766
+ // so they don't get confused with server-loaded content
2767
+ onBeforeUpdate: elementManager.processManuallyAddedElements,
2768
+ // After successful request, tag new server content
2769
+ onCompletePreviousRequest: (loadedPage) => {
2770
+ setTimeout(() => {
2771
+ elementManager.processServerLoadedElements(loadedPage);
2772
+ options.onCompletePreviousRequest();
2773
+ window.queueMicrotask(elementManager.refreshTriggers);
2774
+ });
2775
+ },
2776
+ onCompleteNextRequest: (loadedPage) => {
2777
+ setTimeout(() => {
2778
+ elementManager.processServerLoadedElements(loadedPage);
2779
+ options.onCompleteNextRequest();
2780
+ window.queueMicrotask(elementManager.refreshTriggers);
2781
+ });
2782
+ }
2783
+ });
2784
+ const addScrollPreservationCallbacks = (reloadOptions) => {
2785
+ const { captureScrollPosition, restoreScrollPosition } = scrollPreservation.createCallbacks();
2786
+ const originalOnBeforeUpdate = reloadOptions.onBeforeUpdate || (() => {
2787
+ });
2788
+ const originalOnSuccess = reloadOptions.onSuccess || (() => {
2789
+ });
2790
+ reloadOptions.onBeforeUpdate = (page2) => {
2791
+ originalOnBeforeUpdate(page2);
2792
+ captureScrollPosition();
2793
+ };
2794
+ reloadOptions.onSuccess = (page2) => {
2795
+ originalOnSuccess(page2);
2796
+ restoreScrollPosition();
2797
+ };
2798
+ return reloadOptions;
2799
+ };
2800
+ const originalFetchNext = dataManager.fetchNext;
2801
+ dataManager.fetchNext = (reloadOptions = {}) => {
2802
+ if (options.inReverseMode()) {
2803
+ reloadOptions = addScrollPreservationCallbacks(reloadOptions);
2804
+ }
2805
+ originalFetchNext(reloadOptions);
2806
+ };
2807
+ const originalFetchPrevious = dataManager.fetchPrevious;
2808
+ dataManager.fetchPrevious = (reloadOptions = {}) => {
2809
+ if (!options.inReverseMode()) {
2810
+ reloadOptions = addScrollPreservationCallbacks(reloadOptions);
2811
+ }
2812
+ originalFetchPrevious(reloadOptions);
2813
+ };
2814
+ return {
2815
+ dataManager,
2816
+ elementManager
2817
+ };
2818
+ }
2819
+
2238
2820
  // src/navigationEvents.ts
2239
2821
  function shouldIntercept(event) {
2240
2822
  const isLink = event.currentTarget.tagName.toLowerCase() === "a";
@@ -2280,7 +2862,7 @@ var configure = (options) => {
2280
2862
  progress2.id = baseComponentSelector;
2281
2863
  progress2.innerHTML = settings.template;
2282
2864
  };
2283
- var set2 = (n) => {
2865
+ var set4 = (n) => {
2284
2866
  const started = isStarted();
2285
2867
  n = clamp(n, settings.minimum, 1);
2286
2868
  status = n === 1 ? null : n;
@@ -2329,7 +2911,7 @@ var set2 = (n) => {
2329
2911
  var isStarted = () => typeof status === "number";
2330
2912
  var start = () => {
2331
2913
  if (!status) {
2332
- set2(0);
2914
+ set4(0);
2333
2915
  }
2334
2916
  const work = function() {
2335
2917
  setTimeout(function() {
@@ -2349,7 +2931,7 @@ var done = (force) => {
2349
2931
  return;
2350
2932
  }
2351
2933
  increaseByRandom(0.3 + 0.5 * Math.random());
2352
- set2(1);
2934
+ set4(1);
2353
2935
  };
2354
2936
  var increaseByRandom = (amount) => {
2355
2937
  const n = status;
@@ -2373,7 +2955,7 @@ var increaseByRandom = (amount) => {
2373
2955
  }
2374
2956
  return 0;
2375
2957
  })();
2376
- return set2(clamp(n + amount, 0, 0.994));
2958
+ return set4(clamp(n + amount, 0, 0.994));
2377
2959
  };
2378
2960
  var render = (fromStart) => {
2379
2961
  if (isRendered()) {
@@ -2519,7 +3101,7 @@ var progress_component_default = {
2519
3101
  configure,
2520
3102
  isStarted,
2521
3103
  done,
2522
- set: set2,
3104
+ set: set4,
2523
3105
  remove,
2524
3106
  start,
2525
3107
  status,
@@ -2746,6 +3328,7 @@ var router = new Router();
2746
3328
  export {
2747
3329
  createHeadManager,
2748
3330
  formDataToObject,
3331
+ getScrollableParent,
2749
3332
  hide2 as hideProgress,
2750
3333
  hrefToUrl,
2751
3334
  isUrlMethodPair,
@@ -2758,7 +3341,8 @@ export {
2758
3341
  setupProgress,
2759
3342
  shouldIntercept,
2760
3343
  shouldNavigate,
2761
- urlWithoutHash
3344
+ urlWithoutHash,
3345
+ useInfiniteScroll
2762
3346
  };
2763
3347
  /* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
2764
3348
  * @license MIT */